Reusable tooling for repo-local agentic engineering.
The stack contains schemas, validators, fixtures, and a small CLI for projects that keep their own .go/ JSON/JSONL state next to the code.
For Viggo, Go is the single public repository-work command. Go plan,
Go T123, and Go loop 2h are modifiers; the CLI commands documented below
are internal primitives used by agents, scripts, and tests.
Projects may combine required_stack_version with an immutable stack_ref (vX.Y.Z or a full commit SHA). The minimum version protects compatibility; the ref makes bootstrap and cross-machine continuation reproducible.
Agent work should be clone-readable. A future agent should be able to inspect a repository and understand its project state without needing a central vault task database.
- This repo (
go-workflow-stack): reusable workflow tooling. - Template repo (
go-project-template): starter.go/project-state structure. - Project repos: own their
.go/state and evidence.
For the full practical architecture and application flow, see docs/practical-architecture.md. For the user-facing go/GO/GOO command router, see docs/go-command-router.md. For the current $go-* bridge status, see docs/go-bridge-status.md. For v0.2+ authoring commands, see docs/authoring-primitives.md. For clone-safe bundle handoffs, see docs/export-import-bundles.md. Versioned state upgrades and agent integrations are documented in docs/contract-migrations.md and docs/agent-adapter-protocol.md.
Routing rule: a target repo must own a valid .go/project.json before workflow execution starts. Repositories without that contract fail closed and must use adopt or spike; a vault is never an execution fallback.
Use this stack when you want reusable commands and validation. Use go-project-template when you want to start a new repo that already carries its own .go/ state. A real project should copy/adapt the template and then keep tasks, evidence, decisions, and architecture principles in its own repository.
go-workflow-stack -> validates/operates -> project repo with .go/
go-project-template -> seeds/copies ------^
Clone this repository next to a project repository:
git clone https://github.com/viggomeesters/go-workflow-stack.git
git clone https://github.com/viggomeesters/go-project-template.git
cd go-workflow-stack
make checkOr install the standalone console command; its wheel carries the schemas and minimal fixture and needs no sibling checkout at runtime:
uv tool install --from . go-workflow-stack
go-workflow version --json
go-workflow validate /path/to/projectRun the CLI against a repo-local .go/ project:
python3 cli/go.py validate ../go-project-template
python3 cli/go.py readback ../go-project-template
python3 cli/go.py next ../go-project-templateA substantial assignment can end in a standard HTML handoff that does not require GitHub access. The delivery is generated from one repo-local epic and contains a stakeholder summary, delivered and excluded scope, evidence, limitations, next steps, release identity, disclosure class, and SHA-256 provenance.
New tasks default to shareable_delivery: auto. Approval automatically creates a restricted, released epic delivery when the task uses agent execution, has at least two acceptance criteria, and modifies at least one path outside .go/. Use task create --shareable-delivery required to force the gate or --shareable-delivery none for small/internal work. A required delivery must resolve to exactly one owning epic; generation failure rolls approval back instead of leaving falsely approved work. Autonomous go results expose generated artifacts in deliveries so the handoff can be sent directly. During autonomous shipping, the per-epic delivery lock remains held until ship succeeds or rollback completes, preventing concurrent work from superseding an artifact that recovery later removes.
python3 cli/go.py delivery build ../my-project \
--epic alteryx-flow-generator \
--version 1 \
--status released \
--disclosure restrictedThe command writes a self-contained file and adjacent machine-readable manifest:
.go/deliveries/alteryx-flow-generator-v1/
index.html
manifest.json
No repository browser or GitHub account is needed to open index.html. Build is local and side-effect free outside the repository. Publication is deliberately separate: delivery publish fails closed until an explicit publisher adapter is configured.
Disclosure defaults to restricted. public and link-private builds reject local home paths, credential assignments, credential-file names, and private-key material before creating output. Restricted builds may retain internal detail but record scan_status: blocked so they cannot be mistaken for publication-ready output.
Released and superseded delivery versions are immutable. Corrections use a higher version with --supersedes <delivery-id>; the previous artifact remains auditable.
Check the public template/stack pairing explicitly:
python3 cli/go.py template-check ../go-project-template --jsonInitialize a fresh repo with the current minimal fixture:
python3 cli/go.py init ../my-project --forceApply the public template's .go/ structure to an existing repo:
GO_PROJECT_BRIEF="What this project must achieve" bash scripts/apply-template.sh ../my-projectThe apply command validates the paired template and then creates a project-specific .go identity, vision, hierarchy, and task set. It does not leave the target pretending to be go-project-template.
router <repo> --command GOO --intent <text>: normalizego/GO/GOO/gOo, inspect repo state, and recommend direct handling,spike,auto,go-loop, or task creation. Missing repos aremode=create_repo; existing repos without.goaremode=repair_existing_repo.spike <repo> --brief <text> [--task-scope code|docs]: create/adopt a repo, scaffold repo-complete basics, write.govision/principles/epics/tasks, and validate.codeis the default so generated tasks include CLI/test scope for implementation repos.auto <repo>: hand off control for autonomous execution. It is the machine-readable shape behind Viggo saying baregoin a repo-local project: validate the durable contract, claim the next task, execute, verify, critic, repair, ship, finish, reflect, and continue until done, a repository gate, or budget. Add--emit-handofffor an agent handoff; add--executefor direct execution. Tasks withexecution_mode: agentselect Codex first and Hermes second by default;mechanicaltasks only run declared commands. Agent work uses a write-scoped ephemeral session, followed by a separate read-only deep critic. Generic acceptance is rejected before claim and the built-in semantic critic remains enabled as a structural backstop.go-loop <repo>/loop <repo>: stronger Ralph/Oh-My-Codex-style control-handoff loop; continue selecting/claiming/repairing tasks until done, budget, or blocker.go <repo> --intent <text> --intent-source-ref <ref> --write: materialize the exact instruction asintent_source.textplus SHA-256 and an optional durable origin reference. For a later standalone TelegramGO, pass the preceding message text unchanged and reference that message/session; do not reconstruct the intent from a summary.go <repo> --execution-brief <brief.json> --write|--execute: validate a compactgo-workflow.execution-brief.v1, materialize one task per semantic work unit, and preserve the selected approach plus SHA-256/source provenance on every task.--executecontinues directly into the auto/loop lifecycle in the same invocation; it does not stop after taskification. Invalid briefs fail before creating tasks.recommendation create <repo> --brief <brief.json>: persist the compact handoff at.go/recommendations/pending.json; use--read-onlyfor a strictly non-mutating preview. A later barego <repo> --executepromotes and archives it without needing chat context or another taskification prompt. See advice-to-outcome continuity.delivery build <repo> --epic <id>: generate.go/deliveries/<epic>-vN/index.htmlplus a validatedgo-workflow.delivery.v1manifest without requiring GitHub access.delivery publish <repo> --delivery-id <id>: enter the explicit publisher-adapter boundary; it fails closed while no adapter is configured.task create <repo> ... --shareable-delivery auto|required|none: control the approval-time shareable-delivery gate;autois the default substantial-task policy.task outcome <repo> --task-id <id> --outcome R1 --status verified|blocked|rejected --evidence <proof>: close one requested outcome. Tracked tasks cannot finish until every R# has a terminal disposition and non-empty evidence; autonomous execution returnsblockedand leaves the task active when closure is incomplete.adopt <repo>: create real repo-local.go/project, principles, vision, and hierarchy state from CLI arguments.status <repo> [--json]: summarize route, project, task counts, next work, and dirty state.doctor <repo> --platform wsl --agent hermes: verify Python 3.11+, Git, Bash, Make, uv, agent availability,.govalidity, and the project's minimum stack-version contract.migrate <repo> [--apply]: plan a versioned.gomigration without writes, or explicitly apply and validate it.adapter validate-result <result.json> --phase <phase>: fail-closed validation for the shared Codex/Hermes/custom adapter result protocol.proof validate <proof.json> [--evidence-root dir] [--copy-to path]: validate live Hermes evidence, optionally recompute raw-result hashes, and copy only after all proof gates pass.stack update <repo> --to vX.Y.Z [--apply]: resolve and verify an immutable stack tag, show a dry-run by default, and apply atomically with rollback data only when explicitly requested.epic create <repo> --title <text>: create an epic-lite work package inhierarchy.json.task create <repo> --summary <text> [--epic epic-id | --feature epic.feature]: create an open repo-local task and optionally attach it to an epic or feature.decision create <repo> --title <text> --context <text> --decision <text>: append an ADR-litedecision.recordedevent.init <repo>: create a minimal.go/fixture.validate <repo>: validate.go/JSON and JSONL files.next <repo>: show the first open task.claim <task-id> --repo <repo> --agent <name>: move an open task to active.finish <task-id> --repo <repo> --agent <name> --evidence <text>: move an active task to done and append evidence.dirty-check <repo>: classify dirty Git state against owned paths.readback <repo>: summarize the project from.go/only.route <repo> [--json]: classify a valid.gotarget asrepo-local; otherwise returnmissing-local-contractwith a non-zero exit and anadoptcommand.bundle export <repo> [--output bundle.json]: export a compact.goreadback/task/history bundle without vault access.bundle import <repo> bundle.json [--write]: validate a bundle and, only with--write, store it under.go/imports/as a review/reconcile artifact.
.go/
project.json
architecture-principles.json
vision.json
hierarchy.json
tasks/open/*.json
tasks/active/*.json
tasks/done/*.json
tasks/blocked/*.json
runs/*.jsonl
evidence/*.jsonl
decisions/*.jsonl
deliveries/<delivery-id>/index.html
deliveries/<delivery-id>/manifest.json
imports/*.json
JSON is canonical for current state. JSONL is canonical for lifecycle, evidence, and decision streams. Delivery HTML is a derived stakeholder view paired with a validated JSON manifest; it does not replace task or evidence state. Markdown is a human view only. Import bundles are review artifacts: they never overwrite existing project state unless a later explicit task chooses to reconcile them.
Process locks live under .git/go-workflow-locks so they do not dirty Git state; non-Git fixtures use .go/locks as a fallback.
Every executed run writes .go/runs/latest.json plus .go/runs/resume.sh. The JSON preserves effective budgets, adapters, critic, and ship flags as structured resume_args; the portable shell entrypoint resolves GO_STACK or a conventional sibling/home checkout at resume time. A campaign can therefore move between macOS and WSL without retaining the originating machine's absolute stack path.
Set GO_EXECUTOR_AGENT=hermes on a Hermes-first machine. An explicit --executor-agent still wins for a single run:
export GO_EXECUTOR_AGENT=hermes
python3 cli/go.py go-loop ../my-project --execute --agent hermesHosted CI is deliberately not part of this project. Run the complete Linux/WSL contract locally; it selects an installed Python 3.11+ or uses uv, executes the full suite, and verifies the stack/template pairing:
bash scripts/check-linux.shA live-model acceptance is deliberately opt-in and never reports success when Hermes is absent:
GO_RUN_REAL_HERMES_E2E=1 bash scripts/run-hermes-acceptance.shRun the standalone distribution check and the Python/frontend/existing-repo pilots:
bash scripts/check-pilots.shUse local validation before committing or publishing changes. The check compiles the Python CLI where applicable and validates the template repository contract.
python3 -m pip install -e '.[test]'
python3 -m pytest tests/test_smoke.py -q
make check
bash scripts/check.shInstall the committed launcher as the root-managed release trust anchor. Do not treat the mutable repo copy as its own security proof:
set -euo pipefail
RELEASE_REPO="$PWD"
RELEASE_COMMIT="$(
/usr/bin/env -i HOME=/tmp PATH=/usr/bin:/bin LANG=C.UTF-8 \
GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null GIT_CONFIG_NOSYSTEM=1 \
GIT_NO_REPLACE_OBJECTS=1 \
/usr/bin/git --no-replace-objects -C "$RELEASE_REPO" rev-parse --verify 'HEAD^{commit}'
)"
RELEASE_LAUNCHER="$(/usr/bin/mktemp /tmp/go-release-launcher.XXXXXX)"
trap '/bin/rm -f "$RELEASE_LAUNCHER"' EXIT
/usr/bin/env -i HOME=/tmp PATH=/usr/bin:/bin LANG=C.UTF-8 \
GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null GIT_CONFIG_NOSYSTEM=1 \
GIT_NO_REPLACE_OBJECTS=1 \
/usr/bin/git --no-replace-objects --no-pager -C "$RELEASE_REPO" \
show "$RELEASE_COMMIT:scripts/release-check.sh" >"$RELEASE_LAUNCHER"
sudo /usr/bin/install -o root -g root -m 0755 \
"$RELEASE_LAUNCHER" /usr/local/bin/go-workflow-release-checkRun the pre-tag candidate gate locally without publishing or invoking hosted automation:
/usr/local/bin/go-workflow-release-check --repo "$PWD" 0.3.11 --allow-candidateAfter committing and creating the annotated tag, run the mandatory final gate. It is intentionally local, can run before the release commit or tag is pushed, requires a clean tree, and tests the archived tag payload rather than the mutable checkout:
/usr/local/bin/go-workflow-release-check --repo "$PWD" 0.3.11If a later repair commit must revalidate an existing immutable tag, opt in explicitly:
/usr/local/bin/go-workflow-release-check --repo "$PWD" 0.3.11 --validate-existingExisting-tag validation proves that the tag is an ancestor of HEAD. A shallow checkout is hydrated in an isolated temporary clone from the canonical HTTPS viggomeesters/go-workflow-stack origin so the working checkout remains untouched and historical tag regressions remain available. The historical stack payload never pairs with an adjacent or explicitly supplied project template: --validate-existing refuses GO_PROJECT_TEMPLATE, because executing a historical gate against external mutable state would violate checkout isolation. When a historical release requires the public template suite, the validator uses an explicit release-to-template commit mapping fetched from the canonical HTTPS template origin; v0.3.8 is paired with go-project-template commit 3956fc92f9e99520756d10f08373635182f22d67. Validate current template compatibility separately against the current stack. An isolated /usr/bin/python3 -I launcher builds a minimal environment before Bash starts, so inherited shell functions and startup files cannot affect path resolution. When installed outside the repository, the launcher rejects untrusted origins before executing repository code; existing-tag mode also proves the selected HEAD is reachable from an origin branch and loads the inner validator from that isolated remote clone. Release tools must resolve from the root-managed system path /usr/local/bin:/usr/bin:/bin; install uv there for historical distribution checks instead of relying on a user-writable ~/.local/bin. Release modes are selected only through explicit command-line flags, not inherited shell variables. SSH origins, arbitrary forks, remote helpers, Git replacement refs, Git config injection, Git hooks inherited through environment config, and transport proxy/SSL overrides are rejected or ignored. Local filesystem remotes are accepted only for fixtures with --allow-local-origin.
Review and explicitly apply an immutable project stack update:
go-workflow stack update . --to v0.3.11 --json
go-workflow stack update . --to v0.3.11 --apply --jsonThe repository should contain only synthetic public fixtures. Do not commit private vault data, credentials, customer data, local runtime DBs, or generated machine state.
Public v0.3.11 release. Substantial agent tasks now create restricted immutable stakeholder deliveries automatically at approval, with explicit required/none overrides, feature-aware epic ownership, versioned supersedes, provenance events, and per-epic locking across approval, explicit builds, autonomous ship, and rollback. It retains v0.3.10's deterministic standalone executive HTML, schema-parity validation, privacy boundaries, and separate fail-closed publication adapter.
This project is released under the MIT License. See LICENSE for the full license text.