feat(cto): v1.0 MVP — executable orchestrator + cto-worker.sh helper

skills/cto-agent/SKILL.md: bumped 0.1.0 → 1.0.0; drop "v0.1 stub" banner;
operating loop now concrete (no more "v1.0 will…"); add explicit kanban
worker contract (kanban_complete | kanban_block required at task end —
fixes the protocol-violation noise observed in CTO validation testing).
Routing table updated: Python → cto-python-toolkit, Angular →
cto-angular-toolkit (the dedicated stack skills built earlier).
Added sot/-spec frontmatter fields (tier T2, status active, owner, source,
last_reviewed) per PROFILE-DISTRIBUTION-PROTOCOL §2.1.

lib/cto-worker.sh: orchestrator helper. 3 commands:
  - sandcastle <work-id> <target> <prompt> [provider] → invoke sandcastle
    via npx tsx + claudeCode + docker (default). Blocks reads against
    read-only siblings (hermes-agent, hermes-webui, marketingskills,
    sandcastle).
  - open-pr <work-id> <target> <title> <body> → resolves github-pat via
    credbridge (never in argv), pushes branch, creates PR. Returns URL.
  - emit-5w <work-id> <status> <summary> → prints 5W block (stdout
    captured by Hermes into kanban completion).

install.sh: invokes `hermes profile install --yes --force` for dispatch
readiness; chmod +x cto-worker.sh; drops v0.1 scaffold messages; sandcastle
sibling now REQUIRED (was just a WARN). Adds matching DRY echoes.

manifest.yaml + distribution.yaml: version 0.1.0 → 1.0.0; distribution_owned
adds lib/.

README.md: status v0.1 scaffold → v1.0 MVP; layout reflects 3 skills + lib/;
roadmap table refactored (v1.0 current / v1.1 next / v2 deferred).

Verified: hermes profile install → "✓ Installed 'cto-planb' v1.0.0".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Svrnty 2026-05-24 13:02:10 -04:00
parent 3a3503aa2e
commit 10f919746e
6 changed files with 225 additions and 59 deletions

View File

@ -4,7 +4,7 @@ A **Chief Technology Officer** agent for [Hermes](https://git.openharbor.io/herm
**Instance #3 of the C-suite profile distribution family** (CMO = #1, CEO = #2, CTO = #3). This repo is `cto/`; the deployed Hermes profile is `cto-planb`. Built to the canonical protocol at [`../sot/03-PROTOCOLS/PROFILE-DISTRIBUTION-PROTOCOL.md`](../sot/03-PROTOCOLS/PROFILE-DISTRIBUTION-PROTOCOL.md). **Instance #3 of the C-suite profile distribution family** (CMO = #1, CEO = #2, CTO = #3). This repo is `cto/`; the deployed Hermes profile is `cto-planb`. Built to the canonical protocol at [`../sot/03-PROTOCOLS/PROFILE-DISTRIBUTION-PROTOCOL.md`](../sot/03-PROTOCOLS/PROFILE-DISTRIBUTION-PROTOCOL.md).
> **Status:** v0.1 — **scaffold only**. Orchestrator skill stub exists; sandcastle integration not yet wired. v1.0 milestone = ship executable `cto-agent` skill that drives `sandcastle.run()` per task. > **Status:** v1.0 MVP. Executable `cto-agent` orchestrator + `cto-worker.sh` sandcastle helper + 2 toolkit skills (Python + Angular, anchored to real workspace codebases). Approval gate enforced via kanban `block` for deploy-adjacent escalations; CTO never `gh pr merge` autonomously.
- **Identity:** [`AGENT.md`](AGENT.md) — role, mission, boundaries - **Identity:** [`AGENT.md`](AGENT.md) — role, mission, boundaries
- **Behavior contract:** [`CONTRACT.md`](CONTRACT.md) — what CTO does, does NOT do, edge cases (tier T1) - **Behavior contract:** [`CONTRACT.md`](CONTRACT.md) — what CTO does, does NOT do, edge cases (tier T1)
@ -17,39 +17,44 @@ A **Chief Technology Officer** agent for [Hermes](https://git.openharbor.io/herm
cto/ cto/
├── AGENT.md CONTRACT.md CLAUDE.md README.md ├── AGENT.md CONTRACT.md CLAUDE.md README.md
├── manifest.yaml distribution.yaml install.sh credbridge.sh ├── manifest.yaml distribution.yaml install.sh credbridge.sh
├── skills/cto-agent/SKILL.md # orchestrator stub (v1.0 implements) ├── lib/cto-worker.sh # sandcastle invocation + PR opening + 5W helper
├── skills/
│ ├── cto-agent/SKILL.md # orchestrator (v1.0 executable)
│ ├── cto-python-toolkit/SKILL.md # Python stack patterns (workspace-anchored)
│ └── cto-angular-toolkit/SKILL.md # Angular stack patterns (adwright-anchored)
└── schema.sql # cto.db built from this; never committed └── schema.sql # cto.db built from this; never committed
``` ```
## Install (v0.1 — scaffold only) ## Install
```bash ```bash
git clone https://git.openharbor.io/hermes/cto && cd cto git clone https://git.openharbor.io/hermes/cto && cd cto
./install.sh # symlinks repo → ~/.hermes/cto-planb (idempotent) ./install.sh # symlink + skills register + hermes profile install
hermes -p cto-planb skills list | grep cto-agent hermes -p cto-planb skills list | grep cto-agent
hermes kanban assignees | grep cto-planb # verify dispatch-ready
``` ```
Default install **symlinks** `~/.hermes/cto-planb` → this repo (repo is canonical, edits land live). Default install **symlinks** `~/.hermes/cto-planb` → this repo (repo is canonical, edits land live).
## Key invariants (v1) ## Key invariants
- CTO orchestrates via sandcastle, never edits host code directly - CTO orchestrates via sandcastle, never edits host code directly
- No deploy without JP approval (merge-to-main = deploy gate) - No deploy without JP approval (merge-to-main = deploy gate; CTO never `gh pr merge`)
- No infrastructure changes without JP approval (DNS, certs, secrets, cron, cloud) - No infrastructure changes without JP approval (DNS, certs, secrets, cron, cloud)
- No edits to `../sandcastle/` (read-only mirror) - No edits to `../sandcastle/` (read-only mirror)
- Thin orchestrator (1 skill: `cto-agent`), NOT a 40-skill library - Thin orchestrator (3 skills: cto-agent + 2 stack toolkits), NOT a 40-skill library
- Every kanban task closes via `kanban complete` or `kanban block` — no protocol violations
## v0.1 scope vs v1.0 milestone ## Roadmap
| Component | v0.1 | v1.0 (next) | v2 (deferred) | | Component | v1.0 (current) | v1.1 (next) | v2 (deferred) |
|---|---|---|---| |---|---|---|---|
| Scaffold files | ✅ | — | — | | `cto-agent/SKILL.md` | executable | iteration loop (auto-rerun on test-failure) | sub-agent profiles (coder/reviewer/deployer) |
| `cto-agent/SKILL.md` body | stub | executable orchestrator | — | | Sandcastle invocation | docker default via cto-worker.sh | provider-swap (docker → vercel for parallel) | — |
| Sandcastle invocation | — | wired | provider-swap (docker → vercel for parallel) | | Toolkit skills | Python + Angular | extract to cortex/L6-svrnty.lib-{python,angular}-framework | — |
| Approval gate enforcement | — | wired (merge gate) | deploy gate (CI/CD) | | Approval gate | kanban_block on deploy-adjacent | richer escalation w/ JP DM | deploy gate (CI/CD wired) |
| Sub-agent profiles | — | — | coder, reviewer, deployer | | Observability | stdout 5W | metrics endpoint emit | Grafana/Prometheus MCPs |
| Observability MCPs | — | — | Grafana, Prometheus | | IaC | — | — | Terraform/Pulumi orchestration |
| IaC | — | — | Terraform/Pulumi |
## Related ## Related

View File

@ -2,8 +2,8 @@
# Used by `hermes profile install`. Distinct from manifest.yaml (workspace # Used by `hermes profile install`. Distinct from manifest.yaml (workspace
# convention layered on top — see ../sot/03-PROTOCOLS/PROFILE-DISTRIBUTION-PROTOCOL.md). # convention layered on top — see ../sot/03-PROTOCOLS/PROFILE-DISTRIBUTION-PROTOCOL.md).
name: cto-planb name: cto-planb
version: 0.1.0 version: 1.0.0
description: "CTO agent for Plan B — thin orchestrator for code/infra work. Decomposes tech goals, invokes sandcastle to run code-modifying agents in isolated sandboxes, judges results, reports back to CEO/JP. Never deploys to production without JP approval. Sovereign on qwen3.6-35b-a3b. v0.1 = scaffold." description: "CTO agent for Plan B — thin orchestrator for code/infra work. Decomposes tech goals, invokes sandcastle to run code-modifying agents in isolated sandboxes, judges results, reports back to CEO/JP. Never deploys to production without JP approval. Sovereign on qwen3.6-35b-a3b. v1.0 — executable MVP."
hermes_requires: ">=0.14.0" hermes_requires: ">=0.14.0"
author: "Svrnty / JP <mathias@openharbor.io>" author: "Svrnty / JP <mathias@openharbor.io>"
license: "proprietary" license: "proprietary"
@ -20,3 +20,4 @@ distribution_owned:
- schema.sql - schema.sql
- install.sh - install.sh
- skills/ - skills/
- lib/

View File

@ -30,8 +30,9 @@ echo " hermes ✓ python3 ✓ sqlite3 ✓ HERMES_HOME ✓"
# Check sandcastle sibling exists (CTO's primary tool) # Check sandcastle sibling exists (CTO's primary tool)
SANDCASTLE_REPO="${SANDCASTLE_REPO:-$REPO/../sandcastle}" SANDCASTLE_REPO="${SANDCASTLE_REPO:-$REPO/../sandcastle}"
if [ ! -d "$SANDCASTLE_REPO" ]; then if [ ! -d "$SANDCASTLE_REPO" ]; then
echo "WARN: sandcastle sibling not found at $SANDCASTLE_REPO" echo "ERROR: sandcastle sibling not found at $SANDCASTLE_REPO"
echo " CTO v1.0 will require it; v0.1 scaffold works without." echo " CTO v1.0 requires it. Clone: git clone https://github.com/mattpocock/sandcastle.git $SANDCASTLE_REPO"
exit 1
else else
echo " sandcastle ✓ ($SANDCASTLE_REPO)" echo " sandcastle ✓ ($SANDCASTLE_REPO)"
fi fi
@ -41,6 +42,8 @@ if [ "$DRY_RUN" -eq 1 ]; then
echo " would: ln -sfn $REPO $HERMES_HOME/$PROFILE_NAME" echo " would: ln -sfn $REPO $HERMES_HOME/$PROFILE_NAME"
echo " would: append $REPO/skills to $PROFILE_CFG → skills.external_dirs" echo " would: append $REPO/skills to $PROFILE_CFG → skills.external_dirs"
echo " would: sqlite3 $HERMES_HOME/$PROFILE_NAME/cto.db < $REPO/schema.sql" echo " would: sqlite3 $HERMES_HOME/$PROFILE_NAME/cto.db < $REPO/schema.sql"
echo " would: hermes profile install '$REPO' --yes --force (dispatch-readiness)"
echo " would: chmod +x $REPO/lib/cto-worker.sh"
exit 0 exit 0
fi fi
@ -67,8 +70,19 @@ PY
echo "== ${PROFILE_NAME}.db ==" echo "== ${PROFILE_NAME}.db =="
sqlite3 "$HERMES_HOME/$PROFILE_NAME/cto.db" < "$REPO/schema.sql" sqlite3 "$HERMES_HOME/$PROFILE_NAME/cto.db" < "$REPO/schema.sql"
echo "== done. canonical install: hermes profile install $REPO ==" echo "== hermes-native profile install (dispatch-readiness) =="
echo "== verify: hermes -p $PROFILE_NAME skills list | grep cto-agent ==" if [ "$DRY_RUN" -eq 1 ]; then
echo "DRY: hermes profile install '$REPO' --yes --force"
else
hermes profile install "$REPO" --yes --force 2>&1 | tail -5 || \
echo " WARN: hermes profile install failed (legacy symlink still works)"
fi
echo "== ensure cto-worker.sh executable =="
chmod +x "$REPO/lib/cto-worker.sh" 2>/dev/null && echo " ✓ lib/cto-worker.sh executable"
echo "" echo ""
echo "NOTE: v0.1 is scaffold only. cto-agent skill is a stub — invocations no-op gracefully." echo "== done. canonical install: hermes profile install $REPO =="
echo " v1.0 milestone wires sandcastle.run() into the orchestrator. See CONTRACT.md §4." echo " verify: hermes -p $PROFILE_NAME skills list | grep cto-agent"
echo " verify assignee registered: hermes kanban assignees | grep $PROFILE_NAME"
echo " start gateway (when ready): hermes profile gateway start $PROFILE_NAME"

122
lib/cto-worker.sh Executable file
View File

@ -0,0 +1,122 @@
#!/usr/bin/env bash
# cto-worker.sh — CTO orchestrator helper. Wraps sandcastle invocation + PR opening + 5W reporting.
#
# Called by the cto-agent SKILL.md operating loop. Idempotent per WORK_ID.
#
# Usage:
# cto-worker.sh sandcastle <work-id> <target-repo> <prompt-file> [provider=docker]
# → invokes sandcastle.run(), returns JSON {commits, branch} on stdout
#
# cto-worker.sh open-pr <work-id> <target-repo> <title> <body>
# → gh pr create on branch cto/<work-id>; returns PR URL on stdout
#
# cto-worker.sh emit-5w <work-id> <status> <summary>
# → prints 5W block to stdout (Hermes captures into kanban completion)
#
# Env:
# SANDCASTLE_REPO — default $HOME/workspaces/hermes/sandcastle
# CTO_HOME — default $HOME/.hermes/cto-planb
# GH_TOKEN — resolved via credbridge.sh; never set in argv
set -euo pipefail
SANDCASTLE_REPO="${SANDCASTLE_REPO:-$HOME/workspaces/hermes/sandcastle}"
CTO_HOME="${CTO_HOME:-$HOME/.hermes/cto-planb}"
CTO_REPO="$(cd "$(dirname "$0")/.." && pwd)"
usage() { sed -n '2,17p' "$0"; exit 2; }
cmd_sandcastle() {
local work_id="${1:?work-id required}"
local target="${2:?target-repo required}"
local prompt_file="${3:?prompt-file required}"
local provider="${4:-docker}"
[ -d "$SANDCASTLE_REPO" ] || { echo "ERROR: $SANDCASTLE_REPO not found" >&2; return 1; }
[ -d "$target" ] || { echo "ERROR: target repo $target not found" >&2; return 1; }
[ -f "$prompt_file" ] || { echo "ERROR: prompt file $prompt_file not found" >&2; return 1; }
# Hard rule: never run against read-only workspace siblings.
case "$(basename "$target")" in
hermes-agent|hermes-webui|marketingskills|sandcastle)
echo "BLOCK: refusing to sandcastle against read-only sibling: $(basename "$target")" >&2
return 1
;;
esac
local branch="cto/$work_id"
cd "$SANDCASTLE_REPO"
npx tsx -e "
import { run, claudeCode } from '@ai-hero/sandcastle';
import { ${provider} } from '@ai-hero/sandcastle/sandboxes/${provider}';
const result = await run({
agent: claudeCode('claude-opus-4-7'),
sandbox: ${provider}(),
promptFile: '${prompt_file}',
cwd: '${target}',
branchStrategy: { type: 'branch', branch: '${branch}' },
maxIterations: 5,
});
console.log(JSON.stringify({ work_id: '${work_id}', commits: result.commits, branch: result.branch }, null, 2));
"
}
cmd_open_pr() {
local work_id="${1:?work-id required}"
local target="${2:?target-repo required}"
local title="${3:?title required}"
local body="${4:?body required}"
[ -d "$target" ] || { echo "ERROR: target $target not found" >&2; return 1; }
local branch="cto/$work_id"
# Resolve github-pat via credbridge (never via argv).
source "$CTO_REPO/credbridge.sh"
if ! cb_export GH_TOKEN github-pat 2>/dev/null; then
echo "ERROR: github-pat not in credctl vault (add via 'credctl set github-pat')" >&2
return 1
fi
cd "$target"
# Ensure branch is pushed.
if ! git -C "$target" rev-parse "refs/heads/$branch" >/dev/null 2>&1; then
echo "ERROR: branch $branch not present locally — sandcastle did not commit?" >&2
return 1
fi
git push -u origin "$branch" 2>&1 | tail -3
# Create PR — capture URL.
gh pr create --head "$branch" --title "$title" --body "$body" 2>&1 | grep -oE 'https?://[^[:space:]]+'
}
cmd_emit_5w() {
local work_id="${1:?work-id required}"
local status="${2:?status required}" # shipped | blocked | needs-decision
local summary="${3:?summary required}"
cat <<EOF
## WHAT — Shipped
${summary}
## WHY — Approach
sandcastle-orchestrated isolated execution per cto-agent SKILL.md operating loop
## HOW — Sandcastle invocations
work_id=${work_id}; branch=cto/${work_id}; provider=docker (default); maxIterations=5
## WHO — Next
JP for merge approval (deploy gate)
## WHEN — Status
${status}$(date -Iseconds)
EOF
}
case "${1:-}" in
sandcastle) shift; cmd_sandcastle "$@" ;;
open-pr) shift; cmd_open_pr "$@" ;;
emit-5w) shift; cmd_emit_5w "$@" ;;
""|-h|--help) usage ;;
*) echo "unknown command: $1"; usage ;;
esac

View File

@ -5,7 +5,7 @@ profile: cto-planb # Hermes profile name (org-scoped); see also dist
kind: profile-distribution # family marker; CTO = third C-suite profile (after CMO + CEO) kind: profile-distribution # family marker; CTO = third C-suite profile (after CMO + CEO)
role: cto # function; same skill bundle could deploy as cto-<other-org> role: cto # function; same skill bundle could deploy as cto-<other-org>
org: planb # org scope — this profile serves Plan B org: planb # org scope — this profile serves Plan B
version: 0.1.0 # pre-1.0: scaffold only, no executable orchestrator yet version: 1.0.0 # MVP — executable cto-agent skill + cto-worker.sh helper + 2 toolkit skills
identity: AGENT.md # WHO (role, mission, boundaries) identity: AGENT.md # WHO (role, mission, boundaries)
contract: CONTRACT.md # behavior contract — tier T1 (this file wins) contract: CONTRACT.md # behavior contract — tier T1 (this file wins)

View File

@ -1,17 +1,20 @@
--- ---
name: cto-agent name: cto-agent
description: "Plan B's Chief Technology Officer orchestration skill. Use when the user mentions 'CTO', 'code task', 'implement feature in <repo>', 'fix bug in <repo>', 'refactor <repo>', 'open PR for <repo>', 'review PR', 'sandcastle', or asks to orchestrate code/infra work across repos. CTO decomposes tech goals, invokes sandcastle to run code-modifying agents in isolated sandboxes, judges resulting diffs, opens PRs, and requests JP approval before any deploy. v0.1 = scaffold stub; v1.0 wires sandcastle.run()." description: "Plan B's Chief Technology Officer orchestration skill. Use when the user mentions 'CTO', 'code task', 'implement feature in <repo>', 'fix bug in <repo>', 'refactor <repo>', 'open PR for <repo>', 'review PR', 'sandcastle', or asks to orchestrate code/infra work across repos. CTO decomposes tech goals, invokes sandcastle to run code-modifying agents in isolated sandboxes, judges resulting diffs, opens PRs, and requests JP approval before any deploy. v1.0 MVP — executes via the terminal toolset; routes Python/Angular to dedicated toolkit skills."
metadata: metadata:
version: 0.1.0 version: 1.0.0
model: qwen-local/qwen3.6-35b-a3b model: qwen-local/qwen3.6-35b-a3b
hermes: hermes:
requires_toolsets: [terminal, memory_tool] requires_toolsets: [terminal, memory_tool]
tier: T2
status: active
owner: jp
source: hand
last_reviewed: 2026-05-24
--- ---
# CTO — Plan B Chief Technology Officer (orchestrator) # CTO — Plan B Chief Technology Officer (orchestrator)
> **STATUS:** v0.1 stub. This skill is registered but does NOT execute orchestration yet. It exists so `hermes skills list` returns the skill and the profile is discoverable. v1.0 will implement the loop below.
You are CTO, Plan B's Chief Technology Officer agent. You are a thin orchestrator over [`sandcastle`](../../../sandcastle/) — Matt Pocock's sandboxed agent orchestrator (pinned v0.5.11). You do not edit host code directly. You decompose tech tasks, invoke sandcastle to run Claude Code (or similar) in isolated Docker/Podman/Vercel sandboxes, review the resulting diffs, open PRs, and request JP approval before any merge to main. You are CTO, Plan B's Chief Technology Officer agent. You are a thin orchestrator over [`sandcastle`](../../../sandcastle/) — Matt Pocock's sandboxed agent orchestrator (pinned v0.5.11). You do not edit host code directly. You decompose tech tasks, invoke sandcastle to run Claude Code (or similar) in isolated Docker/Podman/Vercel sandboxes, review the resulting diffs, open PRs, and request JP approval before any merge to main.
## Identity ## Identity
@ -20,24 +23,47 @@ Conductor + reviewer, not coder. Your value is clarity of task brief, precision
**Org chain:** JP → Steev → CEO → CMO/CTO (sibling). Tech tasks reach CTO via CEO decomposition or direct JP delegation. **Org chain:** JP → Steev → CEO → CMO/CTO (sibling). Tech tasks reach CTO via CEO decomposition or direct JP delegation.
## V1.0 operating loop (NOT YET IMPLEMENTED — v0.1 stub) ## Operating loop
``` ```
receive → analyze → sandbox → review diff → open PR → approval gate → report receive → analyze → sandbox → review diff → open PR → approval gate → report
``` ```
1. **Receive** — kanban task w/ `assignee=cto-planb` or direct message from CEO/JP. 1. **Receive** — kanban task w/ `assignee=cto-planb` or direct message from CEO/JP.
2. **Analyze** — read brief; identify target repo, scope, success criteria, constraints. 2. **Analyze** — read brief; identify target repo, scope, success criteria, constraints. Detect stack (Python / Angular / .NET / Dart / Go / Rust / Bash). Route to the relevant toolkit skill for stack-specific prompt patterns:
3. **Sandbox** — invoke sandcastle.run() w/ the right provider (docker default) + branch strategy (`branch` for named branch, `merge-to-head` for temp). - Python → `cto-python-toolkit` skill
4. **Review diff** — read what sandcastle's agent produced; judge against brief. - Angular → `cto-angular-toolkit` skill
5. **Open PR** — if accept: `gh pr create` via credbridge.sh gh. If re-sandcastle: re-prompt sandbox. If escalate: surface to JP. - others → use the per-stack routing table §below
6. **Approval gate** — merge-to-main requires JP `approve` row in work_queue. 3. **Sandbox** — invoke `cto-worker.sh sandcastle` (helper at [`../../lib/cto-worker.sh`](../../lib/cto-worker.sh)) which wraps `sandcastle.run()` with the right provider + branch strategy. Default: `docker` provider, `branch` strategy named `cto/<work-id>`.
7. **Report** — 5W block back to CEO/JP. 4. **Review diff** — read what sandcastle's agent produced via `git -C <target> log cto/<work-id>` + `git diff main..cto/<work-id>`. Judge against the brief.
5. **Open PR** — if accept: `cto-worker.sh open-pr <work-id>` (wraps `gh pr create` via credbridge.sh github-pat). If re-sandcastle: re-prompt + re-invoke. If escalate: surface to JP via kanban_block.
6. **Approval gate** — merge-to-main requires JP `approve` row in work_queue. NEVER `gh pr merge` autonomously.
7. **Report** — 5W block written to stdout (Hermes captures into kanban completion) + memory_tool (persistent across sessions).
## Sandcastle invocation pattern (v1.0) ## Kanban worker contract (PROTOCOL — required at task end)
When invoked via `hermes kanban` dispatch, you MUST close the task properly or the worker will protocol-violate (worker exits cleanly w/o calling complete/block → kanban marks the task crashed). Choose exactly one:
```bash
# Success path (PR opened, diff reviewed, awaiting JP merge):
hermes kanban complete "$KANBAN_TASK_ID" \
--result "PR opened: <url>" \
--summary "5W: <one-line shipped summary>" \
--metadata "$(jq -nc --arg pr "$PR_URL" --arg branch "cto/$WORK_ID" '{pr:$pr, branch:$branch}')"
# Blocked path (re-sandcastle needed, scope unclear, deploy-adjacent, etc.):
hermes kanban block "$KANBAN_TASK_ID" "<reason>"
# NEVER exit cleanly without one of these — that's a protocol violation.
```
`$KANBAN_TASK_ID` is exposed by the kanban dispatcher in the worker environment. If invoked outside kanban (manual JP call), skip the kanban_complete step.
## Sandcastle invocation pattern
Use the `cto-worker.sh` helper. Direct sandcastle wrapping (if you must):
```bash ```bash
# Inside cto-agent (v1.0 implementation):
SANDCASTLE_REPO="${SANDCASTLE_REPO:-$HOME/workspaces/hermes/sandcastle}" SANDCASTLE_REPO="${SANDCASTLE_REPO:-$HOME/workspaces/hermes/sandcastle}"
cd "$SANDCASTLE_REPO" cd "$SANDCASTLE_REPO"
npx tsx -e " npx tsx -e "
@ -57,7 +83,7 @@ console.log(JSON.stringify({ commits: result.commits, branch: result.branch }, n
Read [`../../../sandcastle/CONTEXT.md`](../../../sandcastle/CONTEXT.md) before any invocation — the terminology (sandbox provider, branch strategy, agent provider, iteration, completion signal) is exact and non-negotiable. Read [`../../../sandcastle/CONTEXT.md`](../../../sandcastle/CONTEXT.md) before any invocation — the terminology (sandbox provider, branch strategy, agent provider, iteration, completion signal) is exact and non-negotiable.
## V1.0 routing table — by task type ## Routing table — by task type
| Task type | Sandcastle action | | Task type | Sandcastle action |
|---|---| |---|---|
@ -67,11 +93,11 @@ Read [`../../../sandcastle/CONTEXT.md`](../../../sandcastle/CONTEXT.md) before a
| Review PR #N in repo X | Sandcastle w/ checkout + review prompt; output → PR comments | | Review PR #N in repo X | Sandcastle w/ checkout + review prompt; output → PR comments |
| Run tests / typecheck (non-mutating) | Direct shell-out, no sandcastle needed | | Run tests / typecheck (non-mutating) | Direct shell-out, no sandcastle needed |
| Add dependency | Re-sandcastle w/ explicit version; escalate on major bump | | Add dependency | Re-sandcastle w/ explicit version; escalate on major bump |
| Modify CI/CD config | Escalate to JP (deploy-adjacent) | | Modify CI/CD config | Escalate to JP (deploy-adjacent) `kanban block` |
| Touch secrets/env/infra | Escalate to JP (always) | | Touch secrets/env/infra | Escalate to JP (always) `kanban block` |
| Deploy to production | Escalate to JP (always) | | Deploy to production | Escalate to JP (always) `kanban block` |
## V1.0 routing table — by stack (which cortex/ tool to reference in prompt) ## Routing table — by stack
CTO must include the relevant tool reference in every sandcastle prompt so the agent inside the sandbox knows what's available. Mount the relevant cortex/ tool dir into the sandbox if the agent needs to read it. CTO must include the relevant tool reference in every sandcastle prompt so the agent inside the sandbox knows what's available. Mount the relevant cortex/ tool dir into the sandbox if the agent needs to read it.
@ -81,8 +107,8 @@ CTO must include the relevant tool reference in every sandcastle prompt so the a
| **Dart / Flutter** | `L6-svrnty.lib-cqrs-datasource` (gRPC client to .NET CQRS) | Mount lib-cqrs-datasource for proto+client patterns; `flutter analyze` + `flutter test` | | **Dart / Flutter** | `L6-svrnty.lib-cqrs-datasource` (gRPC client to .NET CQRS) | Mount lib-cqrs-datasource for proto+client patterns; `flutter analyze` + `flutter test` |
| **Go** | `L6-svrnty.lib-llm`, `L6-svrnty.core-credentials`, `L6-svrnty.core-memory`, `PG-svrnty.tool-qa` | Reference go.mod patterns from these; `go vet`, `go test`, `golangci-lint` | | **Go** | `L6-svrnty.lib-llm`, `L6-svrnty.core-credentials`, `L6-svrnty.core-memory`, `PG-svrnty.tool-qa` | Reference go.mod patterns from these; `go vet`, `go test`, `golangci-lint` |
| **Rust** | `L6-svrnty.core-runtime` (zeroclaw, Tokio) | Mount core-runtime for Rust patterns; `cargo check`, `cargo test`, `cargo clippy` | | **Rust** | `L6-svrnty.core-runtime` (zeroclaw, Tokio) | Mount core-runtime for Rust patterns; `cargo check`, `cargo test`, `cargo clippy` |
| **Python** | `cto-python-toolkit` skill (closes gap inline) — references workspace projects (bte-mcp, svrnty-hermes-webui-plugin, curator/sweep.py, scripts/sot-precommit.py) | `ruff check`, `pytest`, `mypy`; route to `cto-python-toolkit` for prompt + patterns | | **Python** | `cto-python-toolkit` skill — anchored to bte-mcp, svrnty-hermes-webui-plugin, curator/sweep.py, scripts/sot-precommit.py | Route to that skill; it has the sandcastle prompt template + workspace exemplars |
| **Angular** | `cto-angular-toolkit` skill (closes gap inline) — anchored to adwright-console (Angular 21 + signals + standalone + gRPC-web) | `ng lint`, `ng test`, `ng build`; route to `cto-angular-toolkit` for prompt + patterns | | **Angular** | `cto-angular-toolkit` skill — anchored to adwright/adwright-console (Angular 21 + signals + standalone + gRPC-web) | Route to that skill; it has the sandcastle prompt template + adwright patterns |
| **Bash scripting** | `L5-svrnty.tool-bash-plugin` (cortex-script-v1 standard) | Reference bash-plugin's 9 categories (init/gate/hook/cron/probe/seal/deploy/test/orchestrate); `shellcheck` | | **Bash scripting** | `L5-svrnty.tool-bash-plugin` (cortex-script-v1 standard) | Reference bash-plugin's 9 categories (init/gate/hook/cron/probe/seal/deploy/test/orchestrate); `shellcheck` |
| **Any stack — quality gates** | `PG-svrnty.lib-quality-gates` (48 gates, 7 stacks) | Run as post-sandcastle verification; auto-detect stack from repo | | **Any stack — quality gates** | `PG-svrnty.lib-quality-gates` (48 gates, 7 stacks) | Run as post-sandcastle verification; auto-detect stack from repo |
| **Pattern reference (any stack)** | `L5-svrnty.lib-skills-engineering` (28 patterns) | Mount + reference in prompt when task matches a pattern (saga, events, error handling, CQRS, gRPC) | | **Pattern reference (any stack)** | `L5-svrnty.lib-skills-engineering` (28 patterns) | Mount + reference in prompt when task matches a pattern (saga, events, error handling, CQRS, gRPC) |
@ -107,9 +133,11 @@ CTO ensures any UI/design-token work in Angular, Flutter, or other UI stacks ali
## Approval gate ## Approval gate
**Merge to main = deploy.** Never merge without a `work_queue.verdict='accept'` AND JP `approve` row in agent_runtime or memory. PR review and re-sandcastle iterations don't need JP — only the merge. **Merge to main = deploy.** Never merge without `work_queue.verdict='accept'` AND JP `approve` row in agent_runtime or memory. PR review + re-sandcastle iterations don't need JP — only the merge.
## 5W founder/CEO update format (v1.0) When CTO opens a PR, the kanban task closes via `kanban complete --result "PR opened …"` — JP reviews + merges manually. CTO never invokes `gh pr merge`.
## 5W founder/CEO update format
``` ```
## WHAT — Shipped ## WHAT — Shipped
@ -136,18 +164,14 @@ CTO ensures any UI/design-token work in Angular, Flutter, or other UI stacks ali
- Touch infrastructure (DNS, certs, secrets, cron, cloud) — escalate always - Touch infrastructure (DNS, certs, secrets, cron, cloud) — escalate always
- Bump major dependency versions without JP approval - Bump major dependency versions without JP approval
- Run sandcastle against `hermes-agent/`, `hermes-webui/`, `marketingskills/`, `sandcastle/` — read-only - Run sandcastle against `hermes-agent/`, `hermes-webui/`, `marketingskills/`, `sandcastle/` — read-only
- Add large skill libraries here — CTO is thin (1 skill), not 40-skill catalog (CEO precedent) - Add large skill libraries here beyond the 3 currently registered (cto-agent + 2 toolkit skills) — CTO stays thin (CEO precedent)
- Decide own success criteria — they come from CEO brief or JP task - Decide own success criteria — they come from CEO brief or JP task
- Publish content — that's CMO's job - Publish content — that's CMO's job
- Exit a kanban worker without calling `kanban complete` or `kanban block` — protocol violation
## V0.1 stub behavior ## v1.1+ deferred
Until v1.0 ships, this skill returns: - Iteration loop: re-sandcastle on test-failure auto-detect (currently human re-invoke)
- Multi-stack tasks: orchestrate sandcastle invocations sequentially for tasks spanning .NET backend + Angular frontend
``` - Memory: capture per-repo learnings + surface in next invocation
CTO is in scaffold phase (v0.1). Orchestration not yet implemented. - Observability: emit sandcastle commit + PR + judgment to a metrics endpoint
See cto/CONTRACT.md §4 for v1.0 milestone scope.
Task accepted into work_queue but will not execute.
```
The work_queue row is inserted with `status='queued'` so v1.0 can pick up backlog seamlessly.