@vegastack/vegafactory 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +417 -0
- package/dist/dashboard-artifact.json +21240 -0
- package/dist/index.js +22752 -0
- package/dist/run-wrapper.js +377 -0
- package/package.json +46 -0
- package/skill/dev-architect/SKILL.md +106 -0
- package/skill/dev-architect/agents/openai.yaml +4 -0
- package/skill/dev-architect/references/ai-agents.md +96 -0
- package/skill/dev-architect/references/conventions.md +113 -0
- package/skill/dev-architect/references/data.md +89 -0
- package/skill/dev-architect/references/infra.md +99 -0
- package/skill/dev-architect/references/mobile.md +75 -0
- package/skill/dev-architect/references/pinned-facts.md +133 -0
- package/skill/dev-architect/references/principles.md +117 -0
- package/skill/dev-architect/references/security.md +90 -0
- package/skill/dev-architect/references/stack.md +38 -0
- package/skill/dev-architect/references/web.md +102 -0
- package/skill/dev-architect/refresh/REFRESH.md +31 -0
- package/skill/dev-architect/refresh/sources.json +239 -0
- package/skill/dev-chronicle/SKILL.md +52 -0
- package/skill/dev-chronicle/agents/openai.yaml +4 -0
- package/skill/dev-chronicle/references/conventions.md +113 -0
- package/skill/dev-chronicle/references/styles.md +75 -0
- package/skill/dev-chronicle/refresh/REFRESH.md +3 -0
- package/skill/dev-chronicle/refresh/sources.json +6 -0
- package/skill/dev-debug/SKILL.md +43 -0
- package/skill/dev-debug/agents/openai.yaml +4 -0
- package/skill/dev-debug/references/conventions.md +113 -0
- package/skill/dev-debug/references/loop-ladder.md +20 -0
- package/skill/dev-debug/refresh/REFRESH.md +3 -0
- package/skill/dev-debug/refresh/sources.json +6 -0
- package/skill/dev-implement/SKILL.md +81 -0
- package/skill/dev-implement/agents/openai.yaml +4 -0
- package/skill/dev-implement/assets/workflows/implement-children.js +12 -0
- package/skill/dev-implement/references/ask-route.md +80 -0
- package/skill/dev-implement/references/changelog-and-chronicle.md +21 -0
- package/skill/dev-implement/references/conventions.md +113 -0
- package/skill/dev-implement/references/ledger-and-resume.md +52 -0
- package/skill/dev-implement/references/parallel-children.md +35 -0
- package/skill/dev-implement/references/worktrees.md +63 -0
- package/skill/dev-implement/refresh/REFRESH.md +3 -0
- package/skill/dev-implement/refresh/sources.json +6 -0
- package/skill/dev-implement/scripts/children.mjs +479 -0
- package/skill/dev-implement/scripts/effective-policy.mjs +694 -0
- package/skill/dev-implement/scripts/evidence-check.mjs +107 -0
- package/skill/dev-implement/scripts/evidence-upload.mjs +181 -0
- package/skill/dev-implement/scripts/learning.mjs +41 -0
- package/skill/dev-implement/scripts/lib/approval.mjs +1182 -0
- package/skill/dev-implement/scripts/lib/gh.mjs +101 -0
- package/skill/dev-implement/scripts/preflight.mjs +153 -0
- package/skill/dev-implement/scripts/questions.mjs +381 -0
- package/skill/dev-implement/scripts/reclaim.mjs +116 -0
- package/skill/dev-implement/scripts/recovery.mjs +213 -0
- package/skill/dev-implement/scripts/worktree.mjs +991 -0
- package/skill/dev-intake/SKILL.md +80 -0
- package/skill/dev-intake/agents/openai.yaml +4 -0
- package/skill/dev-intake/references/ask-route.md +80 -0
- package/skill/dev-intake/references/brief-template.md +89 -0
- package/skill/dev-intake/references/conventions.md +113 -0
- package/skill/dev-intake/refresh/REFRESH.md +3 -0
- package/skill/dev-intake/refresh/sources.json +6 -0
- package/skill/dev-intake/scripts/brief-lint.mjs +87 -0
- package/skill/dev-intake/scripts/lib/approval.mjs +1182 -0
- package/skill/dev-intake/scripts/questions.mjs +381 -0
- package/skill/dev-plan/SKILL.md +54 -0
- package/skill/dev-plan/agents/openai.yaml +4 -0
- package/skill/dev-plan/references/ask-route.md +80 -0
- package/skill/dev-plan/references/conventions.md +113 -0
- package/skill/dev-plan/references/plan-format.md +82 -0
- package/skill/dev-plan/refresh/REFRESH.md +3 -0
- package/skill/dev-plan/refresh/sources.json +6 -0
- package/skill/dev-plan/scripts/lib/approval.mjs +1182 -0
- package/skill/dev-plan/scripts/plan-lint.mjs +319 -0
- package/skill/dev-plan/scripts/questions.mjs +381 -0
- package/skill/dev-review/SKILL.md +76 -0
- package/skill/dev-review/agents/openai.yaml +4 -0
- package/skill/dev-review/assets/review-known-patterns.md.template +32 -0
- package/skill/dev-review/references/conventions.md +113 -0
- package/skill/dev-review/references/cross-agent.md +39 -0
- package/skill/dev-review/references/dispatch-prompts.md +121 -0
- package/skill/dev-review/references/security-axis.md +45 -0
- package/skill/dev-review/refresh/REFRESH.md +5 -0
- package/skill/dev-review/refresh/sources.json +6 -0
- package/skill/dev-setup/SKILL.md +113 -0
- package/skill/dev-setup/agents/openai.yaml +4 -0
- package/skill/dev-setup/assets/agents-section.md.template +24 -0
- package/skill/dev-setup/assets/dev-profile.md.template +102 -0
- package/skill/dev-setup/assets/factory-board.yml.template +162 -0
- package/skill/dev-setup/assets/hooks/decision-nudge.mjs +30 -0
- package/skill/dev-setup/assets/hooks/prompt-skill-mention.mjs +29 -0
- package/skill/dev-setup/assets/hooks/session-end.mjs +14 -0
- package/skill/dev-setup/assets/hooks/session-start.mjs +178 -0
- package/skill/dev-setup/assets/hooks/ship-guard.mjs +738 -0
- package/skill/dev-setup/assets/hooks/skill-activated.mjs +47 -0
- package/skill/dev-setup/assets/hooks/stop-heartbeat.mjs +14 -0
- package/skill/dev-setup/assets/workflows/implement-children.js +12 -0
- package/skill/dev-setup/references/ask-route.md +80 -0
- package/skill/dev-setup/references/conventions.md +113 -0
- package/skill/dev-setup/references/github-app.md +286 -0
- package/skill/dev-setup/references/harness-facts.md +169 -0
- package/skill/dev-setup/references/stack-playbooks.md +124 -0
- package/skill/dev-setup/refresh/REFRESH.md +13 -0
- package/skill/dev-setup/refresh/sources.json +602 -0
- package/skill/dev-setup/scripts/effective-policy.mjs +694 -0
- package/skill/dev-setup/scripts/questions.mjs +381 -0
- package/skill/dev-setup/scripts/ship-policy.mjs +195 -0
- package/skill/dev-ship/SKILL.md +56 -0
- package/skill/dev-ship/agents/openai.yaml +4 -0
- package/skill/dev-ship/references/conventions.md +113 -0
- package/skill/dev-ship/references/runbook.md +72 -0
- package/skill/dev-ship/refresh/REFRESH.md +3 -0
- package/skill/dev-ship/refresh/sources.json +6 -0
- package/skill/dev-ship/scripts/lib/approval.mjs +1182 -0
- package/skill/dev-ship/scripts/ship-gate.mjs +485 -0
- package/skill/dev-status/SKILL.md +56 -0
- package/skill/dev-status/agents/openai.yaml +4 -0
- package/skill/dev-status/references/conventions.md +113 -0
- package/skill/dev-status/refresh/REFRESH.md +3 -0
- package/skill/dev-status/refresh/sources.json +6 -0
- package/skill/dev-status/scripts/effective-policy.mjs +694 -0
- package/skill/dev-status/scripts/status.mjs +311 -0
- package/skill/skill-maintainer/SKILL.md +82 -0
- package/skill/skill-maintainer/agents/openai.yaml +4 -0
- package/skill/skill-maintainer/references/release-ops.md +61 -0
- package/skill/skill-maintainer/references/standards.md +137 -0
- package/skill/skill-maintainer/refresh/REFRESH.md +40 -0
- package/skill/skill-maintainer/refresh/sources.json +103 -0
- package/skill/skill-scan/SKILL.md +59 -0
- package/skill/skill-scan/agents/openai.yaml +4 -0
- package/skill/skill-scan/refresh/REFRESH.md +18 -0
- package/skill/skill-scan/refresh/sources.json +133 -0
- package/skill/skill-scan/scripts/lib/skillspector.mjs +226 -0
- package/skill/skill-scan/scripts/skill-scan.mjs +1002 -0
- package/skill/skillify/SKILL.md +108 -0
- package/skill/skillify/agents/openai.yaml +4 -0
- package/skill/skillify/assets/templates/README.md.template +26 -0
- package/skill/skillify/assets/templates/REFRESH.md.template +16 -0
- package/skill/skillify/assets/templates/SKILL.md.template +27 -0
- package/skill/skillify/assets/templates/evals.json.template +12 -0
- package/skill/skillify/assets/templates/openai.yaml.template +4 -0
- package/skill/skillify/assets/templates/skill.test.ts.template +27 -0
- package/skill/skillify/assets/templates/sources.json.template +6 -0
- package/skill/skillify/assets/templates/trigger-queries.json.template +1 -0
- package/skill/skillify/references/authoring.md +103 -0
- package/skill/skillify/references/eval-playbook.md +112 -0
- package/skill/skillify/refresh/REFRESH.md +23 -0
- package/skill/skillify/refresh/sources.json +6 -0
- package/skill/skillify/scripts/scaffold-skill.mjs +334 -0
- package/skill/skillify/scripts/trigger-check.mjs +209 -0
- package/skill/vegafactory-setup/SKILL.md +77 -0
- package/skill/vegafactory-setup/agents/openai.yaml +4 -0
- package/skill/vegafactory-setup/assets/control-room/boards.md.template +17 -0
- package/skill/vegafactory-setup/assets/control-room/decisions.md.template +5 -0
- package/skill/vegafactory-setup/assets/control-room/group.md.template +44 -0
- package/skill/vegafactory-setup/assets/control-room/onboarding/dispatcher-box.md.template +86 -0
- package/skill/vegafactory-setup/assets/control-room/onboarding/new-repo.md.template +13 -0
- package/skill/vegafactory-setup/assets/control-room/onboarding/new-teammate.md.template +12 -0
- package/skill/vegafactory-setup/assets/control-room/org.md.template +60 -0
- package/skill/vegafactory-setup/assets/control-room/people.csv.template +2 -0
- package/skill/vegafactory-setup/assets/control-room/repos.md.template +7 -0
- package/skill/vegafactory-setup/assets/control-room/rules/CODEOWNERS.template +6 -0
- package/skill/vegafactory-setup/assets/control-room/rules/README.md.template +9 -0
- package/skill/vegafactory-setup/assets/control-room/rules/stats-privacy.md.template +44 -0
- package/skill/vegafactory-setup/assets/control-room/templates/README.md.template +9 -0
- package/skill/vegafactory-setup/references/control-room.md +149 -0
- package/skill/vegafactory-setup/references/conventions.md +113 -0
- package/skill/vegafactory-setup/refresh/REFRESH.md +5 -0
- package/skill/vegafactory-setup/refresh/sources.json +6 -0
- package/skill-integrity.json +252 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Harness facts
|
|
2
|
+
|
|
3
|
+
Verified mechanics of the three harnesses this workflow targets — Claude Code, Codex, Hermes — and the GitHub CLI floor. Everything here is volatile — vendors change these — so each claim carries its source; the refresh contract tracks them. Verified 2026-09-03.
|
|
4
|
+
|
|
5
|
+
## Claude Code
|
|
6
|
+
|
|
7
|
+
- Claude Code does **not** read AGENTS.md natively. The documented pattern is a CLAUDE.md that imports it: a line containing `@AGENTS.md` (import syntax is `@path/to/file`, resolved relative to the containing file, maximum 4 hops of recursion; `@` inside backticks stays literal). <!-- source: CC-MEMORY -->
|
|
8
|
+
- `CLAUDE.local.md` in the project root loads after CLAUDE.md and is meant to be gitignored — leave it alone; it is the user's personal file. <!-- source: CC-MEMORY -->
|
|
9
|
+
- Project skills load from `.claude/skills/<name>/SKILL.md`; personal skills from `~/.claude/skills/`. <!-- source: CC-SKILLS -->
|
|
10
|
+
- The structured question tool is **AskUserQuestion**. It is unavailable in non-interactive runs (`claude -p`); a configurable timeout can auto-submit pre-selected options. <!-- source: CC-TOOLS -->
|
|
11
|
+
- Hooks live in settings files (`.claude/settings.json` project-level) under a `hooks` key mapping event names to command entries. The `Stop` event fires when Claude finishes a turn; its stdin JSON includes `session_id`, `stop_hook_active`, and `last_assistant_message`; a hook keeps the agent going by emitting `{"decision": "block", "reason": "…"}` (or exit 2 with the reason on stderr) — `reason` is shown to the agent. `SessionEnd` cannot block. `SubagentStop` is a separate event — leave it unwired so subagents don't fire nudges. <!-- source: CC-HOOKS -->
|
|
12
|
+
- **Worktrees.** Hook paths do not follow the worktree: `CLAUDE_PROJECT_DIR` "still points at the project root where the session started", while the hook input's `cwd` "is the worktree root, and it moves again when Claude runs `cd`" — a hook that needs the worktree reads `cwd`. A permission approval granted in a worktree is saved to the **main checkout's** `.claude/settings.local.json`, "so it applies in the main checkout and in every other worktree of the repository, and it survives the worktree's removal" (the exception is Windows and the other cases where Claude Code does not use the repository root, where the rule stays with that worktree). Non-interactive `-p` runs "have no exit prompt, so Claude doesn't clean up their worktrees" — cleanup belongs to whatever created them. Claude Code itself refuses to create a worktree when `.claude`, `.claude/worktrees`, or the worktree directory is a symlink. <!-- source: CC-HOOKS -->
|
|
13
|
+
- **Saved dynamic workflows.** A workflow script in `.claude/workflows/` resolves by name from the `Workflow` tool. It must open with a pure-literal `export const meta = { name, description, phases }` — no computed values — and it has no filesystem or Node API access: `Date.now()`, `new Date()` and `Math.random()` throw inside one. Concurrent `agent()` calls are capped at `min(16, cpus - 2)`, one `pipeline()`/`parallel()` call takes at most 4096 items, and a run's lifetime agent count is capped at 1000. Verified 03-09-2026 against claude-code 2.1.247. <!-- source: CC-TOOLS -->
|
|
14
|
+
- **Agent worktree isolation.** `isolation: "worktree"` gives an agent its own worktree and returns its path and branch; the worktree is auto-cleaned only when the agent changed nothing. `worktree.baseRef` is `fresh` (the default — branches from `origin/<default-branch>`) or `head` (branches from local HEAD). A run that must branch from a specific commit tells the agent the sha rather than relying on that setting. Verified 03-09-2026 against claude-code 2.1.247. <!-- source: CC-TOOLS -->
|
|
15
|
+
- **Telemetry.** Claude Code exports OpenTelemetry metrics and log events. `claude_code.skill_activated` is "logged when a skill is invoked, whether Claude calls it through the Skill tool or you run it as a `/` command", carrying `invocation_trigger` (`"user-slash"`, `"claude-proactive"`, `"nested-skill"`); `skill.name` is `"custom_skill"` for user-defined and plugin skills unless `OTEL_LOG_TOOL_DETAILS=1`, which also exports "Bash commands, MCP server and tool names, skill names … and tool input". It is off by default and this workflow never turns it on. Verified 03-09-2026. <!-- source: CC-TELEMETRY -->
|
|
16
|
+
- The Agent SDK's `claude_code` system-prompt preset is Claude Code's own system prompt (`systemPrompt: { type: 'preset', preset: 'claude_code' }`); anything that prompt already says reaches every Claude Code session without a skill repeating it. <!-- source: CC-SDK-PRESET -->
|
|
17
|
+
|
|
18
|
+
## Codex
|
|
19
|
+
|
|
20
|
+
- Codex reads AGENTS.md natively: from `~/.codex/` (global; `AGENTS.override.md` wins over `AGENTS.md`), then from the repo root down to the working directory, one file per directory, concatenated root-first so closer files override. Combined size is capped by `project_doc_max_bytes`, default 32 KiB. There is **no** `@file` import mechanism — layering is directory-based only. <!-- source: CODEX-AGENTS -->
|
|
21
|
+
- Skills load from `.agents/skills/` in each directory from the working directory up to the repo root, plus `~/.agents/skills/` for the user. Frontmatter requires only `name` and `description`; an optional `agents/openai.yaml` adds display metadata and invocation policy. <!-- source: CODEX-SKILLS -->
|
|
22
|
+
- The structured question tool is **`request_user_input`** — collaboration-mode-gated (available in Plan mode; elsewhere it fails fast with a clear error, and it is not available to subagents). Community posts mention an "ask_user_question"/"clarify" tool; that is a proposal, not a shipped tool — do not design against it. <!-- source: CODEX-SKILLS -->
|
|
23
|
+
- Non-interactive mode is `codex exec`: fully unattended, human-input tools unavailable, AGENTS.md discovery unchanged. <!-- source: CODEX-EXEC -->
|
|
24
|
+
- Codex hooks are stable: `~/.codex/hooks.json` or `<repo>/.codex/hooks.json` (inline `[hooks]` tables in config.toml also work); events `SessionStart`, `SessionEnd`, `PreToolUse`, `PostToolUse`, `PermissionRequest`, `UserPromptSubmit`, `SubagentStart`, `SubagentStop`, `PreCompact`, `PostCompact`, `Stop`; the same stdin-JSON contract as Claude Code — `{"decision": "block", "reason": "…"}` or exit 2 blocks, `Stop` carries `stop_hook_active` and `last_assistant_message`, `SubagentStop` is separate — with one gap: `permissionDecision: "ask"` is parsed but unsupported, so a hook that needs a human answer blocks instead. Non-managed hooks run only after the user trusts their exact definition, project-local hooks only when the repo's `.codex/` layer is trusted; `codex exec --dangerously-bypass-hook-trust` runs enabled hooks headless for automation that vets hook sources itself. <!-- source: CODEX-HOOKS -->
|
|
25
|
+
- Project trust is per-path in `~/.codex/config.toml`: a `[projects."<abs path>"]` table with `trust_level = "trusted"`. "If you mark a project as untrusted, Codex skips project-scoped `.codex/` layers, including project-local config, hooks, and rules" — user- and system-level config keep working. A new worktree is a new path, so it needs its own entry before any run there can see the repo's `.codex/` layer. <!-- source: CODEX-CONFIG -->
|
|
26
|
+
- Codex multi-agent is stable: built-in agents `default`, `worker` (implementation) and `explorer` (read-only exploration); custom agents are `.codex/agents/<name>.toml` files, a custom name overriding a built-in of the same name; `agents.max_concurrent_threads_per_session` in config.toml caps parallel threads. <!-- source: CODEX-AGENTS-MULTI -->
|
|
27
|
+
- The multi-agent tools are `spawn_agent`, `wait_agent`, `close_agent` and `list_agents`. **`spawn_agent` has no cwd parameter**, so a spawned agent shares the parent's cwd and its `workspace-write` writable root and cannot write to a sibling worktree. Per-child isolation on Codex is therefore one `codex exec -C <worktree>` process per child, not a spawned agent. Verified 03-09-2026 against Codex CLI 0.149.1. <!-- source: CODEX-AGENTS-MULTI -->
|
|
28
|
+
|
|
29
|
+
- **Telemetry.** OTel log export is **disabled by default**, opted into with an `[otel]` table in config.toml (`exporter = "none"`, `otlp-http`, `otlp-grpc`; with `"none"` Codex "records events but sends nothing"). The documented stream covers "API requests, SSE/events, prompts, tool approvals/results" and names no skill-activation event — which is why skill capture on Codex is a prompt-mention proxy (the skill's name after a dollar sign), recorded as one. Verified 03-09-2026. <!-- source: CODEX-OTEL -->
|
|
30
|
+
|
|
31
|
+
## Hermes
|
|
32
|
+
|
|
33
|
+
- Hermes hooks: a shell `pre_tool_call` hook can block a tool call or fail closed; plugin hooks register `pre_tool_call`, `post_tool_call`, `pre_llm_call` and `post_llm_call` through `ctx.register_hook`, bounded by `plugins.hook_callback_timeout` (default 30s). There is no Stop-style turn hook, so the decision-capture recipe below has no Hermes wiring. <!-- source: HERMES-HOOKS -->
|
|
34
|
+
- The **Curator** is "a background maintenance pass for agent-created skills": it tracks views, uses and patches, moves long-unused skills active → stale → archived, runs on an inactivity check rather than a cron daemon, and never auto-deletes. It maintains skills; it is not a usage-statistics stream. Verified 03-09-2026. <!-- source: HERMES-CURATOR -->
|
|
35
|
+
- Hermes tools: the structured question tool is `clarify`; `delegate_task` spawns subagents; both are ordinary toolset entries (`clarify`, `delegation`), so a headless Hermes run with the toolset off degrades exactly like a Claude Code `-p` run. Skills load from `~/.hermes/skills/` only — no project-level discovery. <!-- source: HERMES-TOOLS -->
|
|
36
|
+
|
|
37
|
+
## Model, effort, and concurrency controls
|
|
38
|
+
|
|
39
|
+
Which model and which reasoning effort a stage runs at is dev.md's `harness-policy:` knob; these are the flags each value turns into.
|
|
40
|
+
|
|
41
|
+
| Harness | Model control | Effort control | Concurrency cap |
|
|
42
|
+
|---|---|---|---|
|
|
43
|
+
| Claude Code | `--model` takes an alias or a full model name — aliases `fable`, `sonnet`, `opus`, `haiku` (plus `best`, `default`, `opusplan`, `sonnet[1m]`, `opus[1m]`), full names look like `claude-sonnet-5`; overrides the `model` setting and `ANTHROPIC_MODEL` <!-- source: CC-CLI --> | `--effort` sets the level for the session; overrides the `modelSettings` and `effortLevel` settings and does not persist <!-- source: CC-CLI --> | `CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH` (nesting depth below the main conversation, default 3; `1` turns nesting off) and `CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS` (simultaneous subagents, default 20) — both env vars, settable under settings.json's `env` <!-- source: CC-SUBAGENT-ENV --> |
|
|
44
|
+
| Codex | `codex exec -m <model>`, or `-c model=<id>` as a config override <!-- source: CODEX-CONFIG --> | `-c model_reasoning_effort=<level>` — the config key the docs demonstrate as `"high"` and do not enumerate, so read the level names off the model's own documentation before promising one <!-- source: CODEX-CONFIG --> | `agents.max_concurrent_threads_per_session` in config.toml caps concurrently open spawned-agent threads, excluding the primary; unset means Codex picks the default <!-- source: CODEX-AGENTS-MULTI --> <!-- source: CODEX-CONFIG --> |
|
|
45
|
+
| Hermes | none documented | none documented | `plugins.hook_callback_timeout` bounds hooks, not agents <!-- source: HERMES-HOOKS --> |
|
|
46
|
+
|
|
47
|
+
Hermes has no documented model or effort flag, so a `harness-policy:` entry never names it as the agent — a policy value that cannot be passed as a flag is a promise the dispatcher cannot keep.
|
|
48
|
+
|
|
49
|
+
Verified 03-09-2026: Claude Code's effort levels are low, medium, high, xhigh and max on Fable 5.1, Fable 5, Opus 5 and Sonnet 5 (high is the default on every model except Opus 4.7, whose default is xhigh), and `ultracode` is a Claude Code setting on top that starts the session at xhigh with dynamic workflows on and needs v2.1.203 or later; `claude --version` here reads 2.1.247 and its `--help` lists the first five. Model ids move, which is why dev.md's `harness-policy:` knob holds them and this file only dates them. <!-- source: CC-CLI -->
|
|
50
|
+
|
|
51
|
+
### The `codex exec` skill-loading drill
|
|
52
|
+
|
|
53
|
+
Whether a headless Codex run discovers project skills on its own decides one thing downstream: if it does not, every dispatched Codex run has to name the SKILL.md path in its prompt. The drill answers it in one command. **The operator runs it by hand.** It starts a real Codex session, so it spends the operator's own Codex quota on the operator's own account — no skill, hook or dispatcher may run it unasked, and dev-setup only ever prints it for the operator to copy. Run it from a scratch directory so the repo's un-ignored `.agents/` is never written to:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
codex login status # must print "Logged in"; a revoked session still prints it — the run below is the real check
|
|
57
|
+
PROBE=$(mktemp -d)
|
|
58
|
+
mkdir -p "$PROBE/.agents/skills/vsk-probe"
|
|
59
|
+
printf -- '---\nname: vsk-probe\ndescription: Probe skill for the harness drill. Use when asked for the probe token.\n---\n\nWhen asked for the probe token, reply with exactly VSK-PROBE-OK-7413 and nothing else.\n' > "$PROBE/.agents/skills/vsk-probe/SKILL.md"
|
|
60
|
+
codex exec -C "$PROBE" --skip-git-repo-check -s read-only 'Use the vsk-probe skill and reply with the probe token, nothing else.'
|
|
61
|
+
codex --version
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The token `VSK-PROBE-OK-7413` in the reply means project skills load under `codex exec`; its absence means they do not. Record the answer with the date and the exact `codex --version` string.
|
|
65
|
+
|
|
66
|
+
Attempted 03-09-2026 on codex-cli 0.149.1 and **not answered**: `codex login status` printed "Logged in using ChatGPT" while the run itself failed with `refresh_token_invalidated` / `token_revoked` (401) before reaching the model — the expired-session case dev.md's Environments section anticipates. The verdict line stays unwritten rather than guessed; re-run the drill after `codex login`. <!-- source: CODEX-SKILLS --> <!-- source: CODEX-EXEC -->
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
## GitHub CLI
|
|
70
|
+
|
|
71
|
+
- Floor **2.94.0**: `gh issue create` and `gh issue edit` take `--type`, `--parent` / `--add-sub-issue`, and `--blocked-by` (edit forms `--add-…`/`--remove-…`) — native issue types, sub-issues and dependencies without the API (GitHub.com; GHES 3.17+ for types and sub-issues, 3.19+ for relationships). <!-- source: GH-CLI -->
|
|
72
|
+
- Floor **2.97.0**: `gh project item-edit --field <name> --value <text>` and `gh project item-list --field <name>` address project fields and single-select options by name; below it, fields need their IDs. <!-- source: GH-CLI -->
|
|
73
|
+
- Below a floor, dev-setup names the missing feature in its report and dev-intake uses the `epic` label and the REST API instead; the floors live here and nowhere else because they move with every gh release.
|
|
74
|
+
|
|
75
|
+
## The hooks package (optional, offered in Round C)
|
|
76
|
+
|
|
77
|
+
Four hooks, one Node file each, written to `.vegastack/hooks/` and wired only on the operator's explicit yes, merged into existing hook config rather than replacing it.
|
|
78
|
+
|
|
79
|
+
| Event | File | What it does | Harnesses |
|
|
80
|
+
|---|---|---|---|
|
|
81
|
+
| `PreToolUse` | `ship-guard.mjs` | Asks before a command the compiled policy says needs the operator's word — a merge, a tag, a publish, a production deploy, a force push. | Claude Code · Codex · Hermes |
|
|
82
|
+
| `SessionStart` | `session-start.mjs` | Requests a bounded verified-context pointer from the local VegaFactory resolver. | Claude Code · Codex |
|
|
83
|
+
| `Stop` | `stop-heartbeat.mjs` | Requests a bounded local checkpoint flush; no continuation or blocking output. | Claude Code · Codex |
|
|
84
|
+
| `Stop` | `decision-nudge.mjs` | Asks whether this session settled a directional choice worth a register line. | Claude Code · Codex |
|
|
85
|
+
|
|
86
|
+
The hook files ship as packaged assets — `assets/hooks/ship-guard.mjs`, `assets/hooks/session-start.mjs`, `assets/hooks/stop-heartbeat.mjs`, `assets/hooks/decision-nudge.mjs` — and are copied verbatim into `.vegastack/hooks/`. The advisory SessionStart adapter is also the shared implementation for `stop-heartbeat.mjs` and `session-end.mjs`: copy `session-start.mjs` beside either consumer even when its SessionStart event is not enabled. Missing CLI/adapter support is silent and does not prove capture. The ship guard and decision nudge remain separate. The wiring shape is doubly nested — matcher groups each holding their own `hooks` array — in Claude Code's `.claude/settings.json` and Codex's `<repo>/.codex/hooks.json` alike (merge into existing hook config, never overwrite): <!-- source: CC-HOOKS --> <!-- source: CODEX-HOOKS -->
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{ "hooks": {
|
|
90
|
+
"PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "node .vegastack/hooks/ship-guard.mjs --harness claude" } ] } ],
|
|
91
|
+
"SessionStart": [ { "hooks": [ { "type": "command", "command": "node .vegastack/hooks/session-start.mjs --harness claude", "timeout": 1 } ] } ],
|
|
92
|
+
"Stop": [ { "hooks": [ { "type": "command", "command": "node .vegastack/hooks/stop-heartbeat.mjs --harness claude", "timeout": 1 }, { "type": "command", "command": "node .vegastack/hooks/decision-nudge.mjs --harness claude" } ] } ]
|
|
93
|
+
} }
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The Codex block is the same file, `--harness codex`, written to `<repo>/.codex/hooks.json`:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{ "hooks": {
|
|
100
|
+
"PreToolUse": [ { "hooks": [ { "type": "command", "command": "node .vegastack/hooks/ship-guard.mjs --harness codex" } ] } ],
|
|
101
|
+
"SessionStart": [ { "hooks": [ { "type": "command", "command": "node .vegastack/hooks/session-start.mjs --harness codex", "timeout": 1 } ] } ],
|
|
102
|
+
"Stop": [ { "hooks": [ { "type": "command", "command": "node .vegastack/hooks/stop-heartbeat.mjs --harness codex", "timeout": 1 }, { "type": "command", "command": "node .vegastack/hooks/decision-nudge.mjs --harness codex" } ] } ]
|
|
103
|
+
} }
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Codex's example intentionally has no matcher, covering every supported tool event. Current [official hook documentation](https://learn.chatgpt.com/docs/hooks) maps shell and unified exec to `Bash`; the supported restrictive grammar is an explicit name union containing `Bash`, optionally anchored. Hosted/specialized tool paths and later stdin transport mean this is not complete remote-effect mediation. Unknown coverage remains unknown. Verified documentation 07-09-2026; actual pinned-harness execution remains qualification evidence. <!-- source: CODEX-HOOKS -->
|
|
107
|
+
|
|
108
|
+
Codex parses `permissionDecision: "ask"` but does not support it, so the ship guard sends Codex `{"decision":"block","reason":"<command> needs the operator's word — run it by hand"}` instead; a Codex operator answers by running the command themselves. <!-- source: CODEX-HOOKS -->
|
|
109
|
+
|
|
110
|
+
Project-local Codex hooks load only once the repo's `.codex/` layer is trusted, and a worktree is a separate path that needs its own trust — dev-setup says so before it offers the wiring. <!-- source: CODEX-CONFIG -->
|
|
111
|
+
|
|
112
|
+
Hermes takes only the ship guard, as a `pre_tool_call` entry in `~/.hermes/config.yaml`:
|
|
113
|
+
|
|
114
|
+
```yaml
|
|
115
|
+
hooks:
|
|
116
|
+
pre_tool_call:
|
|
117
|
+
- command: node .vegastack/hooks/ship-guard.mjs --harness codex
|
|
118
|
+
fail_closed: true
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Hermes has no Stop-style turn hook and no SessionStart event, so only the ship guard wires there; it reuses the Codex block shape because Hermes reads the same `{"decision":"block"}` contract. <!-- source: HERMES-HOOKS -->
|
|
122
|
+
|
|
123
|
+
The ship guard's only source of policy is `~/.vegastack/guard/<owner>__<repo>.json`, keyed by the checkout's origin remote and compiled from `.vegastack/dev.md` — the `## Environments` policy lines, the `gates:` knob, the `repo:` line's default branch and the commands the `## Ship` runbook's `ask:` lines name in backticks — by `scripts/ship-policy.mjs` on the operator's yes, or by `vegafactory guard sync` afterwards. dev.md stays the declared intent a human edits; the JSON is the enforcement copy, outside every worktree, so no task edits it and no commit carries it. The guard never reads dev.md: a run under bypassed permissions could otherwise write `- prod: auto — gh pr merge` into its own worktree's profile and authorise the command it was about to run. With the policy file missing, unreadable, malformed or compiled for another repository, every guarded command asks with a reason naming the file and the sync command; a command whose text touches `.vegastack/guard` is itself on the always-ask list; the managed launch gate performs the compiler comparison and refuses stale policy. The guard reads the command as a shell would — quotes, escapes, `;` `&&` `||` `|` `&`, subshells and dollar-paren command substitution — resolves wrappers (`sudo`, `env`, `nice`, `time`, `timeout`, `xargs`, `sh -c`, a path or an escape on the head) and git and gh global options, then matches the resolved argv: a push's destination in every refspec spelling (`HEAD:main`, `refs/heads/main`, `main:main`, `+main`), force and delete flags in any position, `gh api` on a merge URL, and a probe of text handed to another interpreter. A command inside the shipping family that nothing classifies resolves to ask, never allow.
|
|
124
|
+
|
|
125
|
+
What the guard is not: it runs as the same user as the agent, so it can neither hide its policy from that user nor stop a run that reads credentials or reaches the network outside the shipping verbs. Branch protection and a read-only App token remain the walls; the guard closes the self-authorisation path, refuses what it cannot read, and makes tampering visible.
|
|
126
|
+
|
|
127
|
+
The prose instruction in the AGENTS.md dev section is the portable base on both harnesses; these hooks are deterministic nudges on top, not a replacement.
|
|
128
|
+
|
|
129
|
+
## Headless runs
|
|
130
|
+
|
|
131
|
+
What a dispatcher can rely on when it starts a run with no human at the keyboard.
|
|
132
|
+
|
|
133
|
+
- Hooks fire under `claude -p`: a headless Claude Code run gets the same `PreToolUse` / `Stop` events as an interactive one, which is what lets the ship guard bound a dark build. <!-- source: CC-HOOKS -->
|
|
134
|
+
- Codex refuses non-managed hooks in an unattended run unless the caller vets them: `codex exec --dangerously-bypass-hook-trust` runs the enabled hooks headless, and it is the only way a dispatched Codex run reaches the ship guard at all. <!-- source: CODEX-HOOKS -->
|
|
135
|
+
- Agent teams do not spawn under `-p`: a headless Claude Code run has subagents bounded by `CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH` and `CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS`, and a run needing a team is a run that belongs in an interactive session. <!-- source: CC-SUBAGENT-ENV -->
|
|
136
|
+
- A headless run has no question tool at all, so `VSK_ASK_ROUTE=issue` is what the dispatcher sets: the round goes into the issue with its options and the recommendation, and the next run reads the answer there. <!-- source: CC-CLI -->
|
|
137
|
+
|
|
138
|
+
## What this means for the dev skills
|
|
139
|
+
|
|
140
|
+
- AGENTS.md is the shared instruction file; the one-line CLAUDE.md import makes it reach Claude Code. Keep the marked section small — it counts against Codex's 32 KiB budget along with everything else in AGENTS.md.
|
|
141
|
+
- Any skill that wants to ask the user degrades by `references/ask-route.md`: intake, plan and implement put the round in the issue and stop at `needs-operator` (intake creates the issue first when the round comes before one exists); dev-setup, which can run before any issue exists, writes documented defaults marked `# TODO confirm` instead and says so.
|
|
142
|
+
- Observed 02-09-2026: the `claude_code` preset already carries the current model guidance on autonomy, delivering work, readability and parallel tool calls; Codex and Hermes get none of it. That is why the AGENTS.md conduct paragraph exists and why skill bodies never restate harness behaviour — a restated instruction competes with the harness's own wording.
|
|
143
|
+
- Parallel children use the owned CLI gateway: a registered, currently owned parent passes the canonical `plan-lint --groups --json` result to `vegafactory children run`, then integrates accepted results with `vegafactory children join`. The gateway owns preparation, bounded concurrency, shared acquisition, execution through the checked runtime, durable results and acceptance; the standalone `children.mjs plan` remains non-executing. Harness processes and worktrees are implementation details behind the gateway, not alternate caller-owned executors. The full contract lives in dev-implement's `references/parallel-children.md` and `references/worktrees.md`.
|
|
144
|
+
- The OpenTelemetry stream is **optional and never required**: capture is deterministic without a collector — the dispatcher parses each harness's own run output, SessionEnd hooks cover interactive sessions, and skill invocations come from hook payloads. `OTEL_LOG_TOOL_DETAILS` stays off; it exports exactly the tool arguments a record must never hold.
|
|
145
|
+
- Every target harness spawns subagents (Claude Code's Task tool, Codex agents, Hermes `delegate_task`), so dev.md's `review:` knob means the same thing on each; only a headless run that cannot spawn falls back to a labeled self-review.
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
## Managed hook and native-memory contract — 07-09-2026
|
|
149
|
+
|
|
150
|
+
Configuration is separate from invocation and qualification. The dispatcher validates synchronous `PreToolUse` command hooks with direct `node <resolved checkout guard> --harness claude|codex` argv, quoted paths allowed; wrappers, operators, wrong flags/events, symlinks and absent interpreters refuse. Guard bytes must match the installed package. Claude project/local/user JSON and Codex JSON plus documented inline array-of-tables are inspected together; complex inline hook syntax gets an explicit migration refusal. Merge new owned registrations only when no equivalent event/argv already exists across those sources; preserve user hooks and original files. Do not replace their configuration or silently recompile policy during launch.
|
|
151
|
+
|
|
152
|
+
Check the selected harness in the prepared ordinary or parent worktree and immediately before spawn. The installed owner compiler performs `--check --json` against the checkout's actual origin and current policy, bounded to ten seconds. Stale/missing/unsupported output refuses. A passing configuration check is not proof that a vendor invoked the guard. A local guard subprocess establishes only local invocation; retain the harmless denied-command proof and unchanged-effect evidence from actual harness qualification separately. Same-user hooks are cooperative, and protected remote effects still require server-side permissions.
|
|
153
|
+
|
|
154
|
+
Native memory is excluded only in VegaFactory-managed processes. Pinned metadata: Codex0.153.4 and Claude Code2.1.263. Unknown versions refuse managed execution pending qualification. Claude managed launch currently also refuses because version/help and a cached/raw settings cascade cannot establish effective managed-hook or memory applicability; no SDK dependency or CLI-session probe is implied. Codex overrides `memories.use_memories=false`, `memories.generate_memories=false`, disables memories/import and `features.context_management.experimental_mode`, and retains hooks/project trust for the exact checkout. The optional task-note/search facility is separate from ordinary project instructions. Claude uses `CLAUDE_CODE_DISABLE_AUTO_MEMORY=1` and session `autoMemoryEnabled:false`, without bare/safe mode or disabling CLAUDE.md. No global setting or existing vendor store is changed/read. Controls are supported configuration, not runtime qualification: verify their actual pinned behavior before claiming support. Sources: [Codex configuration](https://learn.chatgpt.com/docs/config-file/config-reference), [Codex context management](https://learn.chatgpt.com/docs/models), [Claude memory](https://code.claude.com/docs/en/memory). <!-- source: CODEX-CONFIG --> <!-- source: CC-MEMORY -->
|
|
155
|
+
|
|
156
|
+
### Local advisory wire contract
|
|
157
|
+
|
|
158
|
+
`session-start.mjs`, `stop-heartbeat.mjs` and `session-end.mjs` require explicit `--harness claude|codex`; configure each enabled event with `timeout: 1` second. The optional SessionEnd registration has the same nested command shape and invokes `node .vegastack/hooks/session-end.mjs --harness <selected>` with that timeout. Installing files does not enable a new event.
|
|
159
|
+
|
|
160
|
+
The adapter reads at most64KiB and waits at most350ms for input, then allows500ms for a local Node CLI invocation. SessionStart invokes `vegafactory learning inspect --source managed-hook --json`; Stop and SessionEnd invoke `vegafactory stats record --source managed-hook`. Their only JSON fields are `{harness,event,sessionId,turnId?,cwd,stopHookActive}`. Events are exactly `SessionStart`, `Stop`, `SessionEnd`; session/turn IDs are1–128 ASCII letters/digits/underscore/hyphen starting with a letter/digit. cwd is an absolute path of at most4096 characters without NUL/newline. It is an identity hint, never a write destination. Each local consumer verifies registered repository/worktree membership and the owned current run/session before any read, flush or lesson lookup; unknown/foreign identities refuse silently. No transcript/tool payload, network, model subprocess, detached upload or Stop continuation is allowed.
|
|
161
|
+
|
|
162
|
+
The stats and learning CLIs implement the managed-hook consumers: the stats path performs registered/current owned-context capture and flush, and the learning path selects verified lessons only for that validated context. Identical repeated events retain identical identity fields, without fabricated timestamps or IDs; failures and unknown identities remain deliberately silent. Implemented consumers and fixture invocation are not actual pinned-vendor qualification.
|
|
163
|
+
|
|
164
|
+
SessionStart emits context only when the local consumer returns `{ok:true}`, a valid `vsk-context:<opaque-id>` pointer and one to three verified lesson rows whose encoded total is at most2KiB. The hook validates each lesson ID and bounded statement, then emits structured `hookSpecificOutput.additionalContext` containing the statements plus an advisory/authority caveat. Pointer-only, empty, malformed, oversized, timed-out or refused results stay silent. Stop/SessionEnd never emit instructions, even on success. Missing CLI/sibling, invalid input/output, unknown source, timeout and re-entered Stop exit0 without output. CLI refusal/missing response is not a persisted-checkpoint receipt. Shell wrappers around the installed JavaScript CLI are unsupported; the adapter verifies the package name/bin layout and both its own and the installed shared-hook bytes against the package integrity manifest, then invokes that JavaScript bin with Node. This assumes an operator-trusted installation, not a publisher attestation or hostile same-user isolation. Retain authored AGENTS.md/CLAUDE.md and hooks. Actual vendor invocation, memory exclusion and complete effect coverage need their own evidence.
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
Codex configuration applicability uses a bounded five-second stdio metadata connection to the installed0.153.4 CLI: only initialize/initialized, hooks/list for the exact cwd, configRequirements/read and config/read. It starts no task or turn, invokes no hook, closes the process afterward, and retains no raw configuration or stderr. Require complete replies, no loader errors, an enabled synchronous exact guard definition/hash/source and compatible managed requirements. Disabled or managed-only-incompatible hooks refuse even when the global hooks feature is true. Effective config must show memory retrieval/generation/import/context disabled. The tested trust override is the invocation-only whole map `-c projects={"/actual/checkout"={trust_level="trusted"}}`; the dotted quoted spelling creates the wrong key in0.153.4. No persisted trust entry is written. [Official app-server protocol](https://learn.chatgpt.com/docs/app-server). <!-- source: CODEX-CONFIG -->
|
|
168
|
+
|
|
169
|
+
The runtime emits the existing recovery arm `remoteEffectCoverage:{kind:"unmanaged-possible",reasonCode:"hook-configuration-only"}` in launch/tick evidence. No configuration inspection, local denial or implemented consumer promotes it to qualified mediation; #137/#158 own receipt validation. The owned child gateway is integrated and reuses the checked executor for every prepared child, but parallel admission still requires canonical groups and current qualified shared-parent ownership. Configuration and local fixtures do not qualify actual vendor execution; raw command descriptions are not execution evidence. Refusal before the OS acknowledges spawn neither records a launch nor consumes a corrections reaction.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Stack playbooks
|
|
2
|
+
|
|
3
|
+
Detection-to-draft mapping for Step 1 and Round C: match the signals, propose the matching draft for `.vegastack/dev.md`, confirm with the user. Every draft is a starting proposal — the user's edits win. Mechanism names here are long-stable; anything version- or vendor-volatile lives in [harness-facts](harness-facts.md) under the refresh contract. Non-GitHub hosting is out of scope for this workflow — the issue/label machinery is GitHub-native.
|
|
4
|
+
|
|
5
|
+
Each playbook fills the same six slots: **detect** (file signals) · **ship draft** (runbook lines) · **changelog** (the `changelog:` knob value and what dev-implement adds per change) · **version identity** (the one place a version lives) · **guards** (from the library below) · **rollback** (one line for `## Ship`).
|
|
6
|
+
|
|
7
|
+
## npm package (published)
|
|
8
|
+
|
|
9
|
+
- **Detect:** `.changeset/config.json`, or a publish workflow / `"private": false` package.json with a registry config.
|
|
10
|
+
- **Ship draft:**
|
|
11
|
+
- `auto: apply pending changesets (changeset version), install so any dependency changes reach the lockfile, commit as chore: release <version>`
|
|
12
|
+
- `ask: tag v<version> and push — the tag triggers the publish pipeline`
|
|
13
|
+
- `guard: tag matches the package version` · `guard: changelog has an entry for the tagged version`
|
|
14
|
+
- `auto: confirm the registry shows the new version; report old → new`
|
|
15
|
+
- **Changelog:** `changesets`. Per behavior-changing branch, dev-implement writes `.changeset/<slug>.md` **directly** — frontmatter `"<package-name>": <patch|minor|major>` (from the brief's version-impact line) plus the entry itself, shaped per dev-implement's changelog rule. `changeset add` (the bare `changeset` prompt) is interactive; never invoke it in a dark run — `changeset version` at release time is the only CLI use. The release changelog is changesets-written — never hand-edited.
|
|
16
|
+
- **Version identity:** `package.json` `version`, changesets-managed. Monorepos: identity is per-package; changesets handles multiple packages natively — the guard reads the released package's manifest. A private workspace root carries no *real* version — pin it at `0.0.0` (some tooling, e.g. `npm sbom` purl generation, requires every package to have one) and never bump it; deleting the field outright breaks such tooling. A lockfile is never the version identity, and package managers differ on whether a workspace's recorded version follows a version-only bump — npm re-records it on the next install, bun does not — so an older version inside a lockfile is a manager behavior to confirm before calling it a defect, and is never repaired by hand-editing the lockfile.
|
|
17
|
+
- **Guards:** changeset-presence (PR-time) · tag↔version · changelog-entry.
|
|
18
|
+
- **Rollback:** `Rollback is roll-forward: revert on main, release previous-good as a new patch, deprecate the bad version on the registry.`
|
|
19
|
+
|
|
20
|
+
## Node web app (deployed, not published — Next.js, Vite, Express, …)
|
|
21
|
+
|
|
22
|
+
- **Detect:** framework config (`next.config.*`, `vite.config.*`, …) with a deploy workflow, platform config (wrangler/Vercel/Netlify), or Dockerfile — and no publish machinery.
|
|
23
|
+
- **Ship draft:**
|
|
24
|
+
- `auto: move the [Unreleased] changelog entries under a new dated version heading, commit`
|
|
25
|
+
- `ask: deploy to production (<the project's deploy command or pipeline>)`
|
|
26
|
+
- `guard: changelog has an entry for the version being released` (when the app versions releases; date-based releases skip the version guard)
|
|
27
|
+
- `auto: smoke-check the deployed URL against the Verify flows; report`
|
|
28
|
+
- **Changelog:** `keep-a-changelog`. Per behavior-changing branch, dev-implement adds one bullet under `## [Unreleased]` (Added/Changed/Fixed/Removed subsection as fits).
|
|
29
|
+
- **Version identity:** `package.json` `version` + the changelog heading, when the project versions releases at all; many apps release by date/deploy — then the changelog heading is the identity and no manifest bump exists.
|
|
30
|
+
- **Guards:** changelog-entry; tag↔version only when the project tags releases.
|
|
31
|
+
- **Rollback:** `Rollback is redeploying the previous known-good build/revision via the platform; a code fix rolls forward through the normal flow.`
|
|
32
|
+
|
|
33
|
+
## Flutter app
|
|
34
|
+
|
|
35
|
+
- **Detect:** `pubspec.yaml` with a `flutter:` section.
|
|
36
|
+
- **Ship draft:**
|
|
37
|
+
- `auto: bump pubspec version (semver + incremented build number), move [Unreleased] changelog entries under the new version, commit`
|
|
38
|
+
- `ask: build and submit the store release / trigger the release pipeline`
|
|
39
|
+
- `guard: tag matches the pubspec version` · `guard: changelog has an entry for the version`
|
|
40
|
+
- `auto: report submitted version + build number`
|
|
41
|
+
- **Changelog:** `pubspec+changelog` — keep-a-changelog `CHANGELOG.md` (also the source for store release notes), with the version bump living in `pubspec.yaml`.
|
|
42
|
+
- **Version identity:** `pubspec.yaml` `version: x.y.z+build` — semver plus a build number the stores require to strictly increase.
|
|
43
|
+
- **Guards:** tag↔version (pubspec read) · changelog-entry.
|
|
44
|
+
- **Rollback:** `Stores do not roll back a released binary: halt the staged rollout if still in progress, then roll forward with a fixed build.`
|
|
45
|
+
|
|
46
|
+
## Python (package or app)
|
|
47
|
+
|
|
48
|
+
- **Detect:** `pyproject.toml`.
|
|
49
|
+
- **Ship draft:**
|
|
50
|
+
- `auto: bump [project] version, move [Unreleased] changelog entries under it, commit`
|
|
51
|
+
- `ask: tag v<version> and push — tag triggers the publish/deploy pipeline`
|
|
52
|
+
- `guard: tag matches the pyproject version` · `guard: changelog has an entry for the version`
|
|
53
|
+
- **Changelog:** `keep-a-changelog`.
|
|
54
|
+
- **Version identity:** `pyproject.toml` `[project] version` (a project pinning it elsewhere names that place in dev.md instead — one place only).
|
|
55
|
+
- **Guards:** tag↔version (pyproject read) · changelog-entry.
|
|
56
|
+
- **Rollback:** `Roll forward: yank the bad release on the index if supported, publish previous-good as a new patch.`
|
|
57
|
+
|
|
58
|
+
## Go module
|
|
59
|
+
|
|
60
|
+
- **Detect:** `go.mod`.
|
|
61
|
+
- **Ship draft:**
|
|
62
|
+
- `auto: move [Unreleased] changelog entries under the new version, commit`
|
|
63
|
+
- `ask: tag v<version> and push — the tag IS the release for module consumers`
|
|
64
|
+
- `guard: changelog has an entry for the tagged version`
|
|
65
|
+
- **Changelog:** `keep-a-changelog`.
|
|
66
|
+
- **Version identity:** the git tag `vX.Y.Z` — Go modules carry no manifest version, so no tag↔version guard exists or is needed.
|
|
67
|
+
- **Guards:** changelog-entry.
|
|
68
|
+
- **Rollback:** `Roll forward and add a retract directive for the bad version in go.mod, released as a new patch.`
|
|
69
|
+
|
|
70
|
+
## Generic / none of the above
|
|
71
|
+
|
|
72
|
+
- **Detect:** none of the signals matched.
|
|
73
|
+
- **Ship draft:** `Ship: merge only` — a valid runbook.
|
|
74
|
+
- **Changelog:** `keep-a-changelog` if the user wants a history; otherwise `none (<reason>)`. A project with an existing convention that matches no knob value records `none (<its convention>)` — the knob never silently mismatches reality.
|
|
75
|
+
- **Version identity / guards / rollback:** none until machinery appears; sections render their TODO line and the self-heal rule covers the rest.
|
|
76
|
+
|
|
77
|
+
## Guard library
|
|
78
|
+
|
|
79
|
+
Each guard is one small shell block with **two uses**: a `guard:` line in `## Ship` that dev-ship runs locally at its runbook position (fast feedback), and the same block as a CI step (the backstop that actually blocks a bad publish — order it **before** the publish step, and offer to write it on the user's yes). Render every `guard:` line in dev.md with its runnable command inline, variables bound (dev-ship reads dev.md, not this file — a guard without its command is an improvisation invitation). Adapt paths/commands per the stack; never offer a guard whose machinery the project lacks.
|
|
80
|
+
|
|
81
|
+
**changelog-entry** — fail when the changelog has no section for the version. Handles both heading styles (`## 1.2.3` changesets, `## [1.2.3]` keep-a-changelog):
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
awk -v ver="$VERSION" '
|
|
85
|
+
$0 == "## " ver || index($0, "## [" ver "]") == 1 { inside = 1; next }
|
|
86
|
+
inside && /^## / { exit }
|
|
87
|
+
inside && /^\[.*\]:/ { next }
|
|
88
|
+
inside { print }
|
|
89
|
+
' "$CHANGELOG" | grep -q '[^[:space:]]' \
|
|
90
|
+
|| { echo "no changelog entry for $VERSION in $CHANGELOG"; exit 1; }
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
(The `^\[.*\]:` skip keeps keep-a-changelog's trailing link-reference block from counting as entry content.)
|
|
94
|
+
|
|
95
|
+
**tag↔version** — fail when the tag disagrees with the manifest:
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
# VERSION per stack ($TAG is the tag being created locally, or $GITHUB_REF_NAME in CI):
|
|
99
|
+
# npm: node -p "require('./package.json').version"
|
|
100
|
+
# Flutter: sed -n 's/^version:[[:space:]]*"\{0,1\}\([0-9][^+" ]*\).*/\1/p' pubspec.yaml
|
|
101
|
+
# Python: python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])" # tomllib needs Python >= 3.11; older: tomli
|
|
102
|
+
[ "v$VERSION" = "$TAG" ] || { echo "tag $TAG != manifest version $VERSION"; exit 1; }
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**changeset-presence** (npm stacks, PR-time) — fail when a behavior-changing branch carries no changeset:
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
npx changeset status --since "origin/$DEFAULT_BRANCH" # or bunx, per the project's runner
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Blind spot: `changeset status` sees changed **workspace packages** only — content outside any package (docs, repo tooling) is invisible to it, so the evidence comment's `**Changelog:**` line stays the human check.
|
|
112
|
+
|
|
113
|
+
## Greenfield playbook
|
|
114
|
+
|
|
115
|
+
No git repo or no origin remote is a greenfield run, not an error. Detection has nothing to read, so the interview supplies intent:
|
|
116
|
+
|
|
117
|
+
1. Ask the intended stack (offer the playbook list above) and whether the project will publish, deploy, or neither — this picks the draft conventions up front.
|
|
118
|
+
2. Offer, each on its own yes: `git init` (default branch `main`) · `gh repo create <owner>/<name> --private` + first push · a stack-appropriate `.gitignore`.
|
|
119
|
+
3. Scaffolding the app itself (create-next-app, flutter create, …) is **not** this skill's job — name the conventional command for the chosen stack and leave running it to the user (or `dev-architect` guidance).
|
|
120
|
+
4. Render dev.md from the chosen playbook's conventions; every section whose machinery doesn't exist yet gets its `TODO — re-run dev-setup when it appears` line. Declined remote → skip labels, record the TODO, and say what was skipped.
|
|
121
|
+
|
|
122
|
+
## Decision-capture hooks
|
|
123
|
+
|
|
124
|
+
The Stop-hook recipe (both harnesses), its wiring, and the hook API facts live in [harness-facts](harness-facts.md) — volatile vendor surface under the refresh contract. Offer it in Round C; write hook files only on the user's explicit yes.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Refresh contract — dev-setup
|
|
2
|
+
|
|
3
|
+
Instructions for the scheduled refresh agent (and any human running a manual refresh). This file plus `sources.json` is the complete freshness contract for this skill.
|
|
4
|
+
|
|
5
|
+
## What this skill claims
|
|
6
|
+
|
|
7
|
+
- **Durable rules** (SKILL.md, assets): the detect-then-ask discipline, the interview rounds and knobs, the marked-section AGENTS.md contract, the default label set, the defaults-plus-TODO fallback. Versionless; the refresh agent NEVER edits these — if evidence invalidates one, open an issue quoting it.
|
|
8
|
+
- **Volatile facts**: everything in `references/harness-facts.md` — Claude Code memory/import/skill/question-tool/hooks/worktree/preset mechanics, Codex AGENTS.md/skills/question-tool/exec/hooks/multi-agent/project-trust mechanics, Hermes hooks, tools and Curator, the three harnesses' telemetry surfaces (Claude Code's `claude_code.skill_activated` event and `OTEL_LOG_TOOL_DETAILS` gate, Codex's opt-in `[otel]` export), the per-harness model/effort/concurrency controls and the recorded `codex exec` skill-loading verdict, the GitHub CLI version floors, plus the shared Stop-hook recipe. Two references are refresh-tracked. `references/harness-facts.md` carries `<!-- source: SOURCE-ID -->` markers on its sentences, matching the registry id by id. `references/github-app.md` carries **no HTML comments on purpose** — a source marker on a path the skill-scan baseline does not already suppress would raise a fresh finding whose suppression needs the operator's word — so that file is pinned whole by `GH-APP-*`, `GH-ACTIONS-OIDC`, `GH-INSTALLATION-TOKENS`, `CF-WORKERS-REQUEST`, and `CF-RATE-LIMIT`. Together they cover App permissions and token-action behavior; Actions OIDC identity/audience/fork behavior; installation-token creation, repository enumeration and revocation; and the Worker request-cache and rate-limiter consistency contracts. `references/stack-playbooks.md` carries only long-stable mechanism names (changesets and its `status`/`version` CLI, keep-a-changelog, store release flows, `gh` subcommands and flags like `--add-readme`, the GitHub contents API shape) — deliberately treated as durable, no pins; if one drifts, open an issue rather than editing in a refresh run.
|
|
9
|
+
|
|
10
|
+
## How to refresh
|
|
11
|
+
|
|
12
|
+
1. Run the shared runner against this registry. Drift in `GH-APP-*`, `GH-ACTIONS-OIDC`, `GH-INSTALLATION-TOKENS`, `CF-WORKERS-REQUEST`, or `CF-RATE-LIMIT` routes to the affected permission, OIDC, mint/verification/revocation, cache, or rate-limit statements in `references/github-app.md`. Drift in another source routes to the marked sentences in `references/harness-facts.md` and to the SKILL.md harness-mechanism mirrors (the three question tools in Step 2, the gh-version and harnesses rows in Step 1, the `@AGENTS.md` imports in Round C and Step 3, the Round C Stop-hook offer, the Round C `harness-policy:` confirmation bullet). Keep each prose correction in the same PR as its runner-produced registry update.
|
|
13
|
+
2. Never auto-apply harness behavior changes; a human reviews — these facts change what dev-setup writes into user projects.
|