I've been experimenting with structuring AI agent workflows the same way I'd structure a team: defined roles, documented conventions, and a CI harness to enforce constraints. This PR lays that foundation in my Rails monorepo, but the real story here isn't the files that got committed. It's the tooling that generated them, and whether it's actually worth using.
The scaffolding came from ai-literacy-superpowers, a plugin-based framework for bootstrapping what it calls a "habitat" — a collection of markdown files that give AI agents (Claude, in this case) the context they need to operate consistently without me repeating myself every session. I followed the first-time tour to get it installed and running. The tutorial walks you through initializing the habitat into an existing repo, and most of the structure it produces landed without much manual intervention: AGENTS.md for team-level conventions, MODEL_ROUTING.md to codify which model handles which class of task, REFLECTION_LOG.md with a reflections/active/ directory for capturing what's working across sessions.
The agent team lives under .claude/agents/: orchestrator, spec-writer, tdd-agent, code-reviewer, and integration-agent. Each file scopes that agent's responsibilities, constraints, and expected outputs. The orchestrator coordinates the others. The tdd-agent writes failing specs first. The code-reviewer checks against the project's existing patterns before approving anything. What I'm actually interested in is the orchestration process itself. The orchestration agent does a good job managing a story all the way through the various agents, and that's where I expect the real value to show up — not in the hooks or the check scripts, but in whether I can hand off a feature and have the agents work it through the full cycle without me babysitting each step. This is the tooling's opinionated take on how an AI agent team should be organized, and I haven't had enough sessions yet to know whether I agree with all of it.
One thing I did have to handle manually was avoiding a competing root CLAUDE.md that would conflict with the existing .claude/CLAUDE.md. Instead of letting two files diverge, I merged the habitat's required sections (Workflow, Build-and-Test, Learnings) directly into the existing file. Less surface area, fewer places for context to drift.
The CI piece is a Gitea Actions workflow (.gitea/workflows/ai-literacy.yml) backed by scripts/ai-literacy-check.sh. This repo runs self-hosted Gitea, not GitHub Actions, so none of the standard habitat tooling translates directly. The check script validates that required files exist and that the harness constraints are in place. It's not sophisticated — it's a guardrail to catch when someone (or some agent) removes or moves something important. I also added one explicit rule to .claude/CLAUDE.md: once pre-commit checks pass on a feature branch, commit and open a PR without waiting for a separate confirmation. AI agents tend to pause and ask permission at every boundary, which is fine when you're exploring but breaks flow when you've already established the working agreement.
Getting here wasn't entirely smooth. Two issues broke auto-edit mode and forced me to step through file updates manually, which was painful enough that it's worth documenting.
The first was a path mismatch: HARNESS.md got generated inside .claude/HARNESS.md but the hook expected it at the project root. The hook never found the file, so the check always failed. The second was a JSON encoding bug in the drift-check hook. The script at ~/.claude/plugins/cache/ai-literacy-superpowers/ai-literacy-superpowers/0.91.0/hooks/scripts/drift-check.sh was building a multi-line message and writing it into a JSON string without properly escaping newlines, which broke the output parsing. The fix is replacing the encoding block with:
if [${#drift_signals[@]} -gt 0 ]; then
message="HARNESS.md may be out of date. Changes detected:"
for signal in "${drift_signals[@]}"; do
message="${message}"$'\n'"- ${signal}"
done
message="${message}"$'\n'"Run /harness-audit to check for drift."
# JSON-encode: escape backslash and quote, then join lines with \n (valid JSON).
encoded=$(printf '%s' "$message" \
| sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' \
| awk 'BEGIN{ORS=""} {if (NR>1) printf "\\n"; printf "%s", $0}')
printf '{"systemMessage": "%s"}\n' "$encoded"
fi
Worth noting: that fix edits the locally cached hook, so any future tool update will overwrite it. And the change won't take effect in a running Claude Code session — you need to start a new session before it kicks in.
Two other gaps didn't make this cut. The orchestrator.md and integration-agent.md both hardcode gh pr create and other GitHub CLI commands that won't work against Gitea. I'll need either a Gitea CLI wrapper or conditional logic in those agent files. The other is the plugin-installed advisory hook that checks for HARNESS.md at the repo root — this repo correctly uses .claude/HARNESS.md per the init spec, so the check is stale, but it's non-blocking.
What I can't tell you yet is whether any of this actually improves how I work with AI agents across sessions. The habitat is in place, the conventions are version-controlled, and the CI harness will complain if something gets removed. Future posts will get into whether the orchestration delivers on its premise.
Comments 0
Leave a Comment
No comments yet. Be the first to share your thoughts!