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:
parent
3a3503aa2e
commit
10f919746e
39
README.md
39
README.md
@ -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
|
||||||
└── schema.sql # cto.db built from this; never committed
|
├── 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
|
||||||
```
|
```
|
||||||
|
|
||||||
## 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
|
||||||
|
|
||||||
|
|||||||
@ -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/
|
||||||
|
|||||||
26
install.sh
26
install.sh
@ -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
122
lib/cto-worker.sh
Executable 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
|
||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -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.
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user