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:
12
harnesses/composites/hugo-content-airouter/v1/harness.yaml
Normal file
12
harnesses/composites/hugo-content-airouter/v1/harness.yaml
Normal 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
|
||||
29
harnesses/contexts/hugo-content-workspace/v1/CLAUDE.md
Normal file
29
harnesses/contexts/hugo-content-workspace/v1/CLAUDE.md
Normal 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.
|
||||
55
harnesses/contexts/hugo-content-workspace/v1/finalize.sh
Executable file
55
harnesses/contexts/hugo-content-workspace/v1/finalize.sh
Executable 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 ==="
|
||||
19
harnesses/contexts/hugo-content-workspace/v1/harness.yaml
Normal file
19
harnesses/contexts/hugo-content-workspace/v1/harness.yaml
Normal 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: []
|
||||
63
harnesses/contexts/hugo-content-workspace/v1/init.sh
Executable file
63
harnesses/contexts/hugo-content-workspace/v1/init.sh
Executable 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 ==="
|
||||
Reference in New Issue
Block a user