feat: hugo-content-workspace + hugo-content-airouter harnesses

New context: hugo-content-workspace/v1
- init.sh: clones hugo-{customer}-content at HUGO_CONTENT_BRANCH and
  hugo-{customer}-integration at main via gitea-ssh-accelerators
- finalize.sh: detects changes, commits content repo first then
  integration repo; skips silently if no changes
- CLAUDE.md: instructs the agent to work in /workspace/content/

New composite: hugo-content-airouter/v1
- Combines airouter/v1 + gitea-ssh-accelerators/v1 + hugo-content-workspace/v1
- Label-gated to airouter dispatchers (ESO secret required)

Used by cms-proxy /ai/{customer}/draft endpoint.
This commit is contained in:
Paul O'Reilly
2026-06-24 07:10:05 +12:00
parent 8167035b6b
commit dd0d9e5c0a
5 changed files with 178 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
kind: composite
name: hugo-content-airouter
version: 1
description: "Hugo content AI assistant — Airouter model + Gitea SSH + content/integration repo clone"
# Airouter label gate — only dispatchers with the ESO airouter secret claim these tasks.
requires_labels: [airouter]
layers:
- context: airouter/v1
- context: gitea-ssh-accelerators/v1
- context: hugo-content-workspace/v1

View File

@@ -0,0 +1,29 @@
# Hugo Content Assistant
You are an AI content assistant for a Hugo website. Your job is to draft or revise content as instructed.
## Working directory
`/workspace/content/` — this is the Hugo content repo. The site structure is:
```
content/ Hugo content files (Markdown with frontmatter)
data/ Site data YAML (navigation, site config, component data)
static/ Static assets (images, favicons)
```
The integration repo (build pipeline) is at `/workspace/integration/` — read-only reference, do not modify it unless explicitly asked.
## How to work
1. Read existing content files to understand the site's voice, structure, and conventions before writing.
2. Make changes to files in `/workspace/content/`. Create new files in the right Hugo directory (`content/`, `data/`, etc.).
3. Use Hugo frontmatter conventions: `---` delimited YAML at the top of every Markdown file.
4. Keep Markdown content clean — no inline HTML unless unavoidable.
5. Do not touch files outside `/workspace/content/` unless the user's request explicitly requires integration changes.
## Output
Your changes will be automatically committed and pushed when you exit. You do not need to run git commands — just write the files.
Summarise what you changed at the end of your response.

View File

@@ -0,0 +1,55 @@
#!/bin/bash
# hugo-content-workspace/v1 finalize.sh
# Detects and commits any changes made by the agent.
# Content repo is committed and pushed first, then integration repo.
set -euo pipefail
echo "=== hugo-content-workspace/v1 finalize.sh ==="
: "${HUGO_CUSTOMER:?HUGO_CUSTOMER is required}"
: "${HUGO_CONTENT_BRANCH:=staging}"
commit_repo() {
local repo_dir="$1"
local branch="$2"
local label="$3"
if [ ! -d "${repo_dir}/.git" ]; then
echo "${label}: no .git directory, skipping"
return 0
fi
cd "${repo_dir}"
# Check for any modifications (tracked or untracked)
if git diff --quiet HEAD 2>/dev/null && [ -z "$(git ls-files --others --exclude-standard)" ]; then
echo "${label}: no changes detected"
return 0
fi
# Stage all changes
git add -A
# Double-check — after staging, is there anything to commit?
if git diff --cached --quiet; then
echo "${label}: nothing staged after add -A"
return 0
fi
local msg="AI content update — ${HUGO_CUSTOMER} (${HUGO_CONTENT_BRANCH})"
if [ "${label}" = "integration" ]; then
msg="AI integration update — ${HUGO_CUSTOMER}"
fi
git commit -m "${msg}"
git push origin "${branch}"
echo "${label}: committed and pushed to ${branch}"
}
# 1. Content repo — push to the requested content branch
commit_repo /workspace/content "${HUGO_CONTENT_BRANCH}" "content"
# 2. Integration repo — push to main
commit_repo /workspace/integration "main" "integration"
echo "=== hugo-content-workspace/v1 finalize.sh complete ==="

View File

@@ -0,0 +1,19 @@
kind: context
name: hugo-content-workspace
version: 1
description: "Hugo site workspace: clone content + integration repos, auto-commit changes on exit"
requires: [git-access]
provides: [hugo-workspace]
scripts:
init: "./init.sh"
finalize: "./finalize.sh"
env:
# Injected by dispatcher from task project_id — set as HUGO_CUSTOMER
HUGO_CUSTOMER: ""
# Branch to check out in the content repo. Pass via runtime.env in the task.
HUGO_CONTENT_BRANCH: "staging"
AGENT_WORKING_DIR: "/workspace/content"
secrets_required: []

View File

@@ -0,0 +1,63 @@
#!/bin/bash
# hugo-content-workspace/v1 init.sh
# Clones the Hugo content and integration repos for a customer site.
# Content repo is checked out at HUGO_CONTENT_BRANCH; integration at main.
set -euo pipefail
echo "=== hugo-content-workspace/v1 init.sh ==="
: "${HUGO_CUSTOMER:?HUGO_CUSTOMER is required (set via runtime.env in task submission)}"
: "${HUGO_CONTENT_BRANCH:=staging}"
GITEA_HOST="gitea.oreillyit.nz-accelerators"
ORG="accelerators"
CONTENT_REPO="hugo-${HUGO_CUSTOMER}-content"
INTEGRATION_REPO="hugo-${HUGO_CUSTOMER}-integration"
CONTENT_URL="git@${GITEA_HOST}:${ORG}/${CONTENT_REPO}.git"
INTEGRATION_URL="git@${GITEA_HOST}:${ORG}/${INTEGRATION_REPO}.git"
mkdir -p /workspace/content /workspace/integration /workspace/.agent-output
# Clone content repo at the requested branch
echo "Cloning content repo: ${CONTENT_URL} (branch: ${HUGO_CONTENT_BRANCH})"
if git clone --branch "${HUGO_CONTENT_BRANCH}" \
-c core.symlinks=false \
"${CONTENT_URL}" /workspace/content; then
echo "Cloned content repo at branch ${HUGO_CONTENT_BRANCH}"
else
echo "ERROR: Failed to clone content repo ${CONTENT_URL}" >&2
exit 1
fi
# Configure git identity in content repo
git -C /workspace/content config user.name "AI Content Assistant"
git -C /workspace/content config user.email "agent@oreillyit.nz"
# Clone integration repo at main (read context, rarely modified by agent)
echo "Cloning integration repo: ${INTEGRATION_URL} (branch: main)"
if git clone --depth 1 --branch main \
-c core.symlinks=false \
"${INTEGRATION_URL}" /workspace/integration; then
echo "Cloned integration repo"
else
echo "WARNING: Could not clone integration repo — non-fatal, proceeding without it" >&2
fi
# Configure git identity in integration repo if it was cloned
if [ -d /workspace/integration/.git ]; then
git -C /workspace/integration config user.name "AI Content Assistant"
git -C /workspace/integration config user.email "agent@oreillyit.nz"
fi
# Ensure .gitignore in content repo excludes secrets
GITIGNORE=/workspace/content/.gitignore
if [ -f "$GITIGNORE" ]; then
if ! grep -q "^\.env$" "$GITIGNORE" 2>/dev/null; then
printf '\n# Agent-added safety exclusions\n*.env\n.env\n*.key\n*.pem\n' >> "$GITIGNORE"
fi
fi
export AGENT_WORKING_DIR="/workspace/content"
echo "AGENT_WORKING_DIR=/workspace/content"
echo "=== hugo-content-workspace/v1 init.sh complete ==="