Synaptory User Guide
SPQ-first delivery guidance for Claude Code, Codex, and Cursor.
Synaptory User Guide
Governed multi-agent delivery on Claude Code, Codex, and Cursor.
Synaptory turns an AI coding host into a governed delivery system. Bounded delivery roles perform the work, capability profiles guide optional runtime selection, and advancement occurs only when the lifecycle kernel validates the required receipts, evidence, and human decisions.
Start here
New users should follow Getting Started. It covers all three hosts, CLI sign-in, SPQ initialization, and the first Cycle.
The forward delivery path is SPQ. Existing Scrum and Kanban projects remain available during their retirement period, but new projects should use explicit build_mode: spq.
Current compatibility detail: an omitted
build_modeis still interpreted as Scrum by the current initializer. Until that product default changes, setbuild_mode: spqexplicitly. Do not rely on inference.
The SPQ lifecycle
SPQ is a scope-driven lifecycle with an integration barrier. A Cycle admits a bounded set of Work Units, executes them through governed roles, integrates the admitted result to the shared trunk at its barrier, and then either opens another Cycle or moves to Acceptance.
Four stages. Commit, Sync and Checkpoint are recorded events, not stages and not gates.
flowchart LR
discovery[DISCOVERY] --> baseline{Baseline approval}
baseline --> cycle[CYCLE]
cycle --> barrier{Barrier: all admitted work, or none}
barrier --> decision{Continue or accept?}
decision -->|Another Cycle| cycle
decision -->|Go-live| acceptance[ACCEPTANCE]
acceptance -->|Not the final one| cycle
acceptance -->|Final| complete[COMPLETE]
The events sit alongside those stages rather than inside them: Commit seals the admitted set and opens the Cycle, Sync records that one Cycle waited on another's result and how it cleared, and Checkpoint records the demonstration, the barrier verdict and the integrated trunk revision. Sync has zero or more occurrences and blocks nothing -- what blocks a Work Unit is an unsatisfied dependency.
The kernel—not prompt memory—selects the next ceremony, role, and legal transition. A failed check, missing receipt, stale dispatch, or unresolved human gate stops advancement.
The delivery hierarchy
| Level | Purpose |
|---|---|
| Engagement | The approved baseline, the shared trunk, and every Acceptance. Ended by the final Acceptance and nothing else. |
| Cycle | A scope-defined increment with its own admitted set, source region, barrier and Checkpoint. The only unit of parallelism. |
| Work Unit | The atomic implement-and-verify unit, governed by receipts and Definition of Done, carrying its own declared path scope. |
Three levels, not five. An earlier revision of this page described a Coordination Cycle above child Cycles above Workstreams; SPD-194 retires both of those layers. Two Cycles run concurrently because their declared source regions do not overlap, not because something above them coordinates them -- see ADR-035.
Hosts and execution runtimes are different
A host is the application where you invoke Synaptory: Claude Code, Codex, or Cursor. An execution runtime profile is an eligible adapter and placement selected for a governed attempt. Installing the plugin on a host does not enable runtime federation by itself.
The nine delivery roles map onto four runtime capability profiles:
| Capability profile | Delivery roles |
|---|---|
| Analyst | Research Advisor |
| Planner | Project Owner, Solution Architect |
| Producer | Software Engineer, Platform Engineer, Technical Writer |
| Prover | Quality Engineer, Code Reviewer, Compliance Engineer |
Capability profiles compose skills; they grant no authority. See Hosts and Runtimes for the installation, certification, placement, compliance, and cross-host boundaries.
Human gates and evidence
SPQ deliberately has more than one human decision:
| Gate | Human responsibility |
|---|---|
| Baseline approval | Confirm the Discovery baseline before Commit. |
| Commit scope | Approve the non-empty set of ready Work Units admitted to the Cycle. |
| Cut | Authorize withdrawing unfinished work, with a reason. The one valve. |
| Checkpoint close | Accept the demonstrated increment on its integrated trunk revision, and choose another Cycle or Acceptance. |
| Acceptance / complete release | Accept the release evidence and authorize completion. Only the final Acceptance closes the engagement. |
Sync is not a gate. It records a dependency having cleared and authorizes nothing, so there is no Sync entry to confirm and no Sync to clear.
Between gates, roles operate inside an exact execution envelope. Each governed stage writes a dispatch-bound receipt, and verification is replayed before the kernel advances. See Enforcement.
What Synaptory produces
- Requirements, approved baselines, and architecture decisions
- Working code and infrastructure
- Unit, integration, end-to-end, security, and regression evidence
- Per-stage receipts bound to the selected role, attempt, and dispatch, with runtime identity when applicable
- Sealed Cycle declarations, recorded cuts, and barrier verdicts naming the integrated trunk revision
- Acceptance evidence, release reports, and operational documentation
- Tracker updates through the configured local, GitHub, Jira, Teamwork, or Linear adapter
Control Plane
The browser Control Plane complements repository-owned state:
- Cycles (
/cycles) shows SPQ Cycle telemetry. - Attempts (
/attempts) shows runtime progress, directives, evidence, and outcomes. - Quality, Cost, Reliability, Audit, and Projects provide scoped operational views.
Git and the governed local state remain authoritative for lifecycle advancement. The Control Plane reports what was delivered to it; it is not a second scheduler.
Legacy lifecycles
Scrum and Kanban are maintained for existing projects while retirement is planned. They are not the recommended starting point, and host certification is not uniform:
- Codex and Cursor certify SPQ; Scrum and Kanban are explicitly uncertified on those hosts.
- Legacy Multi-Spec partitions Scrum/Kanban tracking. SPQ uses native Cycle identity instead and ignores
SYNAPTORY_ACTIVE_SPEC. - Migration must use governed initialization/migration operations; never edit pipeline state by hand.
See Migrating to SPQ before changing an existing project.
Guide map
Start
SPQ concepts
Product and operation
What's next
- What's next: Synaptory Platform - the step from
plugin to platform, and what it does and does not change for this install
Guides
- SPQ Delivery
- SPQ Setup Runbook
- Resuming Pipelines
- Using the Control Plane
- Release and Acceptance
- Migrating to SPQ
Legacy
Reference
Getting Started
This guide takes a new user from installation to the first governed SPQ Cycle on Claude Code, Codex, or Cursor.
What you will set up
Synaptory has two required components:
- A host plugin for Claude Code, Codex, or Cursor.
- The
synaptoryCLI, shared across hosts and projects on the same laptop.
Runtime federation is optional and comes later. First establish a working SPQ project on one host.
1. Choose a host
| Host | Minimum and scope | Invocation | Important boundary |
|---|---|---|---|
| Claude Code | Claude Code 2.1.196 or newer | /synaptory | Full host-native hook surface. Reload after installation or update. |
| Codex | Codex CLI 0.147.0 or newer; standard, non-regulated SPQ | $synaptory | Project bootstrap is dry-run first, installs nine managed profiles, and requires a new task after apply. |
| Cursor IDE | Staff Team marketplace or licensed local install | /synaptory | SPQ is certified. Reload the window after install. |
| Cursor CLI/headless | cursor-agent with project MCP preflight | /synaptory in the agent prompt | The IDE's local-plugin directory is not loaded by the CLI; preflight is mandatory. |
Use a single host as the writer for an active governed stage. Sharing the same repository does not create a supported cross-host handoff workflow.
2. Install the CLI and sign in
Install once per laptop:
# macOS / Linux
curl -fsSL https://synaptory.h3t.co/cli/install.sh | bash
# Windows PowerShell
iwr -useb https://synaptory.h3t.co/cli/install.ps1 | iex
Then sign in with your organization identity:
synaptory login
synaptory whoami
synaptory projects list
For a machine without a browser, use synaptory login --device. See Install the CLI for PATH, update, checksum, and keychain details.
3. Install the host plugin
Claude Code
Run these commands inside Claude Code:
/plugin marketplace add https://github.com/h3tech-ai/marketplace
/plugin install synaptory@h3tech-ai
Restart Claude Code or reload the window. For automatic updates, open /plugin, select the h3tech-ai marketplace, and turn Auto-update on.
Verify with:
/synaptory doctor
Codex
Run these commands in a terminal:
codex plugin marketplace add https://github.com/h3tech-ai/marketplace
codex plugin add synaptory@synaptory-dev
Start a new Codex task and invoke $synaptory. On the first project run, Synaptory checks readiness and presents a bootstrap dry-run if the managed profiles or project configuration are missing. Review the planned files, confirm apply, and then start another new task so Codex discovers the nine profiles.
Codex refuses regulated baa_enforced projects on this standard path. Do not interpret a successful install as regulated certification.
Cursor IDE
An organization administrator imports GitHub repository h3tech-ai/marketplace into the Cursor Team marketplace and makes the synaptory plugin available. Install it from the team catalog, then run:
synaptory skills sync --host cursor
Reload Cursor and verify with /synaptory doctor.
Synaptory is not distributed through the public cursor.com marketplace because that marketplace requires open-source packages.
Cursor CLI or CI
The IDE convention ~/.cursor/plugins/local is not loaded by cursor-agent. For a licensed checkout, wire and verify the project MCP before every headless run:
python3 plugin-cursor/scripts/preflight.py --project <project> --write
cd <project>
cursor-agent mcp enable synaptory
python3 plugin-cursor/scripts/preflight.py --project <project>
The final command must print ready: and exit 0. For an explicit plugin path, use agent --plugin-dir ./plugin-cursor.
4. Bind the repository to a project
At the repository root, identify the Control Plane project and select SPQ explicitly:
# .synaptory.yaml
project_id: "my-project"
build_mode: "spq"
engagement_mode: "structured"
tracker:
backend: "local"
You can ask the host to generate the file:
Initialize this project for governed SPQ delivery.
Review the proposed file before approving it. In particular, confirm project_id, build_mode: spq, repository paths, and tracker configuration.
Why explicit? SPQ is the recommended lifecycle, but the current compatibility default for an omitted
build_modeis still Scrum. Explicit configuration prevents a new project from entering the legacy lifecycle.
5. Declare the source region and the trunk
A Cycle declares the repository paths it may address and the one shared branch it integrates into. There are no lanes to define and no parallelism to switch on -- concurrency is a consequence of the path scope each Work Unit declares.
spq:
source_region:
- "api/"
- "web/"
trunk_ref: "refs/heads/dev"
Overlapping source regions are refused at declaration. That refusal is what lets two Cycles run concurrently without either one inspecting what the other admits.
6. Start the first Cycle
Give Synaptory an outcome, not an instruction to mutate lifecycle files:
Use SPQ to deliver account sign-in with audit logging. Start Discovery and
show me the baseline before Commit.
The normal path is:
- Discovery frames the outcome, the constraints, the source region and the evidence expectations.
- Baseline approval is a human gate. It needs a measured calibration sample, not just a sha -- review and explicitly approve or request changes.
- Commit admits a non-empty set of ready Work Units, each declaring its path scope, and seals the declaration. Nothing joins the Cycle afterwards.
- The Cycle dispatches the exact next role for each Work Unit and validates its receipt. Disjoint units run concurrently with nothing to enable; intersecting ones run in the order they declared.
- A cut, if the Cycle cannot finish its admitted set. Explicit reason, backlog return, and a key a later Commit can name. It never moves the baseline.
- The barrier evaluates the admitted set minus the recorded cuts -- all of it or none -- and integrates the result to the shared trunk.
- Checkpoint records the demonstration, the verdict, the integrated trunk revision and the cut list, and asks whether to open another Cycle or proceed to Acceptance.
- Acceptance runs the release roles and stops for the human release decision. Only the final one closes the engagement.
There is no Sync to wait for. Sync records that one Cycle waited on another's published result and how it cleared; it has zero or more occurrences and blocks nothing. What blocks a Work Unit is an unsatisfied dependency, and /synaptory status says which one.
At any boundary, ask:
/synaptory status
On Codex, use $synaptory and ask for status in the same request. Do not run the lifecycle Python modules directly and never edit .synaptory/.orchestrator/pipeline-state.json.
7. Add runtime federation only when needed
The host-native path is enough for the first Cycle. To inspect the runtimes the machine can serve:
synaptory runtimes list
synaptory runtimes doctor
Runtime selection remains inert until an enabled runtimes: policy is present in an SPQ project. The selected delivery role maps to one of four capability profiles, and policy cannot select anything outside allowed_profiles. Capability profiles do not grant authority; the dispatch envelope does.
Read Hosts and Runtimes before enabling it.
8. One shape, and when to open a second Cycle
There is one delivery shape: a Cycle. Open a second concurrent Cycle when the work has its own cadence and a source region that does not overlap the first -- that is the whole condition, and no layer above them composes anything.
- Work that belongs to one increment: one Cycle. Continue with
- Work with its own cadence and a disjoint region: a second Cycle, with its own
Lead, Crew and Checkpoint. Neither waits for the other.
- Work that cannot be ordered -- a mutually dependent pair -- goes in one
Cycle. It cannot be split across two, and the declaration refuses the split and names the route.
- Existing Scrum, Kanban, or Multi-Spec project: follow
Next reading
Install the synaptory CLI
The synaptory CLI handles sign-in, session state, governed skill/policy delivery, diagnostics, telemetry, and optional Runtime Bridge operations. Install it once per laptop — the same install works across Claude Code, Codex, Cursor, and every Synaptory project you can access.
The CLI is shipped separately from all host plugins. The download script detects your OS/architecture, verifies SHA-256, and places the binary on your $PATH.
macOS / Linux
curl -fsSL https://synaptory.h3t.co/cli/install.sh | bash
That's it. The script:
- Detects
darwin-arm64,darwin-amd64,linux-amd64, orlinux-arm64. - Resolves
latest.json, then downloads the versioned binary andsha256sums.txtfromsynaptory.h3t.co/cli/. - Verifies the SHA-256 before installing.
- Installs to
~/.local/bin/synaptory. - Tells you the line to add to
~/.zshrc/~/.bashrcif~/.local/binisn't on your$PATH.
After install:
synaptory version # confirm the CLI is on PATH
synaptory login # sign in via Entra (browser opens)
The login step prints the projects you can see right after sign-in, so you'll know immediately whether the operator has provisioned you correctly.
Custom install location
Set SYNAPTORY_CLI_PREFIX if ~/.local isn't where you want it:
SYNAPTORY_CLI_PREFIX=$HOME/Tools curl -fsSL .../cli/install.sh | bash
# installs to $HOME/Tools/bin/synaptory
Updating the CLI
Re-run the same one-liner. The script is idempotent and overwrites with the latest version.
Uninstall
rm ~/.local/bin/synaptory
synaptory logout # if you want the keychain cleared first
Windows
iwr -useb https://synaptory.h3t.co/cli/install.ps1 | iex
The script:
- Detects amd64 (the only Windows build we publish).
- Resolves
latest.json, then downloadssynaptory-windows-amd64.exeandsha256sums.txtfromsynaptory.h3t.co/cli/. - Verifies the SHA-256.
- Installs to
%USERPROFILE%\bin\synaptory.exe. - Adds
%USERPROFILE%\binto your userPATHif it isn't already (no admin needed; survives reboot).
If the script added a directory to PATH, open a new PowerShell window so the updated PATH is loaded. Then:
synaptory version
synaptory login
Updating
Re-run the same one-liner.
Uninstall
Remove-Item "$env:USERPROFILE\bin\synaptory.exe"
synaptory logout # not strictly required; the keychain entry is harmless
Commands every user should know
These are the commands you'll run directly. Hooks call the rest for you.
| Command | What it does |
|---|---|
synaptory login | Open a browser, sign in via Entra. Session is cached in the OS keychain. No --project flag — one sign-in covers every project you're a member of. |
synaptory whoami | Print the cached UPN and session expiry. First check when something feels wrong. |
synaptory projects list | List the projects you can see, with your role in each. |
synaptory status | Full diagnostic — control-plane URL, session state, skill cache, outbox depth. |
synaptory logout | Clear the cached session. The next governed host session will prompt you to sign in again. |
synaptory version | Print the CLI version. Useful when reporting issues. |
Less common, but good to know
| Command | When to use it |
|---|---|
synaptory skills list | See which skills are in your local cache. |
synaptory outbox flush | Manually flush queued telemetry if the control plane was unreachable. Normally automatic on session start. |
synaptory projects current | Print the project slug resolved from .synaptory.yaml / SYNAPTORY_PROJECT_ID. |
Switching projects
You don't. The same session works across every project you're a member of. The CLI auto-detects which project you're in by walking up from your current directory looking for .synaptory.yaml:
# .synaptory.yaml
project_id: taskflow-pilot
Telemetry and skill fetches stamp that slug onto requests. The server checks your membership against project_members per request — if you've been removed from a project, the next call returns 403 and the CLI quarantines the event for the operator to review.
What happens behind the scenes
You won't normally run these operations. Claude Code uses native session hooks; Codex and Cursor obtain the same governance outcomes through their project bootstrap, supported hooks, and MCP integration:
- The host integration checks CLI/session readiness. If the cached session cannot be refreshed, it stops governed mutation and asks you to sign in.
- It refreshes the project's governed skill and policy cache.
- It loads host-native instructions/rules and reads canonical lifecycle state.
- It flushes durable telemetry when connectivity is available.
If any of those fail, you'll see a clear error message pointing at the fix.
Troubleshooting
| Symptom | Fix |
|---|---|
command not found: synaptory | The install dir isn't on $PATH. Rerun the install one-liner; it prints the line to add to your shell rc. |
synaptory: control plane URL not configured | The CLI binary you installed was built without SYNAPTORY_CP_URL stamped in. Ask your H3Tech operator for a rebuilt binary. |
synaptory: Entra OAuth is not configured | Same operator-side issue — the Entra tenant/client IDs weren't stamped at build time. |
login: you are not a member of any project yet | Your sign-in worked but the operator hasn't added your UPN to any project. Email ops@h3t.co with your UPN. |
403 user is not an active member of project '<slug>' mid-session | Either you've been removed from the project, or the slug in .synaptory.yaml is wrong. Run synaptory projects list to see what you can access. |
| Session expired mid-work | Run synaptory login again. No --project flag is needed; start a fresh host turn if the integration asks you to reload state. |
| macOS Gatekeeper blocks the binary | Run xattr -d com.apple.quarantine ~/.local/bin/synaptory. The binary is unsigned for the pilot; production builds will be notarized. |
For anything else, run synaptory status and include the output when you report the issue to ops.
How Synaptory works
Synaptory is a governed delivery system that runs inside supported coding hosts and records authoritative lifecycle state in a shared control plane. The host helps people and agents do the work; Synaptory decides what is authorized, what evidence is required, and whether the work may advance.
If you want to install and run a first Cycle, start with Getting Started.
Component map
flowchart LR
U["Delivery user"] --> H["Host adapter<br/>Claude Code · Codex · Cursor"]
H --> K["SPQ governance<br/>dispatch + advance"]
K --> R["Runtime adapter<br/>optional federation"]
R --> A["Governed attempt"]
A --> E["Events + receipt + evidence"]
E --> K
H --> C["synaptory CLI"]
C <--> CP["Control Plane API"]
CP <--> DB[("Canonical state<br/>policy · audit · telemetry")]
CP <--> W["Control Plane web"]
| Component | What it owns |
|---|---|
| Host adapter | Host-native instructions, skills, agents, hooks, and MCP wiring; the user's lifecycle conversation. |
| SPQ governance | State transitions, gate prerequisites, dispatch authority, idempotency, receipt validation, and advancement. |
| Runtime adapter | Execution of one already-authorized dispatch envelope on a certified runtime profile. |
synaptory CLI | Identity, project resolution, governed skill/policy sync, diagnostics, telemetry outbox, and Runtime Bridge operations. |
| Control Plane API | Project authorization, canonical lifecycle state, runner leases, runtime supervision, skills/policy, and telemetry ingestion. |
| Control Plane web | Human views for Cycles, Acceptances, attempts, evidence and administration. |
Host and runtime are different roles
The host is where you talk to Synaptory. The runtime is where one authorized attempt executes.
You can use Claude Code as the host and keep all attempts there. SPQ runtime federation is an operator preview: an attempt can be executed on a certified Codex, Cursor, or managed Claude profile through the synaptory runtime commands, but enabling runtimes: does not make an ordinary Work Unit route there, because no host dispatch path calls the selector yet. Installing multiple host packages alone does not connect them, and a runtime cannot approve its own evidence or advance canonical state.
See Hosts and Runtimes for the support and profile matrix.
Why the control plane matters
A host-native session is useful but not sufficient for governed delivery. The control plane provides:
- per-user and per-project authorization;
- canonical SPQ state across sessions;
- versioned policy and governed skill delivery;
- immutable Cycle, Work Unit, attempt, and gate records;
- leases and fencing for supervised workers;
- evidence, cost, quality, reliability, and audit views.
This separation prevents a chat summary, a stale worker, or a runtime's private session state from becoming the delivery record.
How a Work Unit travels
- The host re-reads the current Cycle and Work Unit.
- The dispatch kernel checks state, dependencies, selected role, policy, and
budget.
- The host runs the dispatched role through its own runtime.
Runtime selection, the signed dispatch envelope, and adapter-prepared execution contexts exist as components and are not yet on this path. See Hosts and runtimes for what is and is not wired.
- Supervision records typed events; the runtime produces artifacts and a receipt.
- The advance kernel validates identity, binding, required evidence, and Checkpoint policy.
- Only then may the Work Unit advance. Human gates still require explicit approval.
Retries create new attempts. They never erase the history of the previous attempt.
Identity, skills, and policy
synaptory login establishes the user's Entra identity and stores the session in the OS credential store. The control plane checks project membership per request.
Host packages contain the integration scaffold. Governed skill and policy content is fetched through the CLI and tied to the authenticated project context. No source-control token is a substitute for Synaptory project membership.
For headless environments, use synaptory login --device.
Control Plane views
Delivery users most often use:
/cyclesfor Cycle stage, gates, source region, Crew and Work Units;/attemptsfor runtime state, evidence, and supervision history;/projectsfor project configuration and access; and/quality,/cost,/reliability, and/auditfor governed outcomes.
The same pages are role-aware and server-scoped to the caller's permissions.
What's next
Architecture
This page maps the SPQ control flow onto Synaptory's local and hosted components. It is intended for operators and integrators; most delivery users only need How Synaptory works.
Trust boundaries
flowchart TB
subgraph Local["User or runner environment"]
H["Claude Code / Codex / Cursor"]
HA["Host adapter"]
CLI["synaptory CLI"]
RT["Runtime adapter"]
WS["Bound workspace"]
H --- HA
HA --- CLI
CLI --- RT
RT --- WS
end
subgraph Control["Synaptory Control Plane"]
API["FastAPI"]
DB[("Postgres")]
WEB["Next.js"]
API --- DB
WEB --- API
end
CLI <-->|"authenticated HTTPS"| API
The host can propose operations. The dispatch kernel authorizes them. The runtime adapter can execute only the envelope it receives. The advance kernel alone decides whether evidence is sufficient to advance. The human alone approves human gates.
Governed attempt sequence
sequenceDiagram participant User participant Host as Host adapter participant CP as Control Plane participant Runtime as Runtime adapter participant Evidence as Receipt/evidence User->>Host: Continue Work Unit Host->>CP: Read canonical Cycle + Work Unit CP-->>Host: State, policy, manifest binding Host->>CP: Request governed dispatch CP-->>Host: Authorized envelope + attempt ID Host->>Runtime: Execute envelope Runtime-->>CP: Typed supervision events Runtime->>Evidence: Artifacts + receipt Host->>CP: Request Checkpoint/advance CP->>Evidence: Validate binding and proof CP-->>Host: Advanced or refused with reasons Host-->>User: Canonical outcome
An agent completion message is not an advancement signal. The host must report the canonical result returned after validation.
Static and application surfaces
| URL pattern | Served by | Purpose |
|---|---|---|
/, /home, /projects, /cycles, /attempts, analytics and administration pages | Next.js web | Role-aware Control Plane UI. |
/auth/*, /api/web/* | Next.js web | Browser authentication and web-facing API routes. |
/v1/* | FastAPI | CLI, lifecycle, runtime, policy, and telemetry API. |
/get-started | Static web asset | Short multi-host installation landing page. |
/docs/getting-started.html | Generated static documentation | Standalone onboarding guide. |
/docs/user-guide.html | Generated static documentation | Complete user guide. |
/cli/* | Static distribution | CLI installers, release metadata, and binaries. |
See URLs for the public URL map.
Runtime supervision
A registered runner advertises certified profiles and obtains time-bounded leases from the control plane. Lease renewal establishes continued ownership. Fencing rejects a stale worker after ownership changes.
Runtime output is reduced to typed, bounded supervision events; arbitrary runtime prose does not become canonical state. The attempt record includes terminal outcome, failure class, budget facts, receipt location, and the envelope authority used to produce it.
Local one-shot commands can inspect local attempts. Cross-machine control requires a live control-plane runner/worker path, and the user-facing result must distinguish “recorded locally” from “delivered to the running worker.”
Deployment components
| Component | Implementation | Responsibility |
|---|---|---|
| Edge/static routing | Caddy | TLS, routing, static downloads and docs. |
| Web | Next.js | Role-aware Control Plane pages. |
| API | FastAPI | Auth, project/lifecycle/runtime/policy services. |
| Database | Postgres | Canonical and operational records. |
| Observability | Grafana and telemetry pipeline | Operational and delivery signals. |
| CLI distribution | Static release tree | Installers and versioned binaries. |
| Host distributions | Claude marketplace, Codex plugin, Cursor package | Host-native integration scaffold. |
Data ownership
| Data | Authority |
|---|---|
| Cycle, Work Unit, gate, attempt, and release state | Control Plane canonical store |
| Project configuration | .synaptory.yaml plus validated control-plane policy |
| Source and generated artifacts | Bound project/worktree storage |
| Runtime-native sessions | Ephemeral/non-canonical |
| Receipts and verification evidence | Attempt artifacts plus accepted control-plane records |
| Tracker issues | External projection; never the sole lifecycle authority |
What's next
Identity and Access
Who you are (Entra — any H3Tech identity can sign in), whether you're an admin (
synaptory-admins), and what projects you can see (project_members).
synaptory has three identity questions, and each is answered in a different place:
| Question | Answered by | Where it's checked |
|---|---|---|
| Who are you? | Entra OAuth (UPN claim) | At sign-in; baked into the SYNAPTORY1 token |
| Are you an admin? | Entra group membership (grp claim) | At sign-in; baked into the SYNAPTORY1 token |
| Can you see project X? | project_members table | Per request, server-side, against the live DB |
The first two are token-time — set at sign-in and immutable for the token's lifetime (~24h). The third is request-time — re-evaluated on every API call, so revoking access takes effect within seconds of the next request.
Sign-in (the normal path)
Three OAuth audiences exist, all backed by one Entra app registration (SYNAPTORY_CP_ENTRA_CLIENT_ID). The same app holds two platform sections in Azure: a Web platform with a client secret, and a Mobile/desktop platform for PKCE.
| Caller | Flow | Redirect URI |
|---|---|---|
| Control Plane browser | Authorization-code with client_secret | https://synaptory.h3t.co/auth/callback |
synaptory CLI | PKCE public client | http://127.0.0.1/auth/callback (loopback exception, random port) |
After Entra issues an ID token, the API exchanges it for a SYNAPTORY1 token:
SYNAPTORY1.<base64url(payload)>.<base64url(ed25519_sig)>
Payload carries sid, upn, grp, iat, exp. There is no prj claim — that was the V1.5 design and was replaced. Project access is a per-request check against project_members, not a token claim.
The Ed25519 signing key lives on disk in dev (settings.signing_key_path) and in Azure Key Vault in prod (kty OKP, curve Ed25519, loaded by api/synaptory_api/tokens.py KeyVaultSigner). The public key is exposed at GET /v1/public-key so the CLI can verify signed config offline.
Groups: synaptory-admins (and synaptory-users)
Per ADR-024, sign-in is not group-gated — any H3Tech Entra identity that passes token verification can log in. Group membership drives one thing: admin.
synaptory-admins— the admin role. Grants access to every/v1/admin/*endpoint and the admin-only pages. Members without it sign in as regular users.synaptory-users— no longer a login gate. It's retained only to seed the dev/on-prem local-auth slots and as a documentation marker; Synaptory does not require it for access.
A user with no project membership still signs in — they just see an empty scope until an operator adds them to a project (project_members).
The grp claim is a list, so admins carry synaptory-admins. ADR-019 retired the /console/* and /portal/* URL trees; every page lives at root URLs now, and admin-only entries are hidden from the sidebar (and gated server-side) for callers without synaptory-admins.
Group membership changes in Entra propagate at the next sign-in — the existing token's grp claim is frozen until expiry.
Project membership
Identity tells the API who you are; the project_members table tells it what you can see. Every project-scoped endpoint calls check_project_membership(db, claims.upn, project_id) (see api/synaptory_api/security.py) which returns:
| Outcome | Status | Reason |
|---|---|---|
| Project doesn't exist | 404 | (anti-leak — no row existence disclosure) |
| Project archived | 403 | Archived projects are read-locked |
| User not a member | 404 | Returned as 404, not 403 — anti-enumeration |
| User membership revoked | 404 | Same as above |
| Active member | 200 | Proceed |
The "not a member returns 404" pattern is deliberate. A 403 would let an attacker enumerate project slugs.
Membership is granted via ./synaptory api projects add-member <slug> <upn> (CLI on the prod VM) or via the project's Members tab in the Control Plane (project admins can self-serve).
Local-auth fallback
For dev and on-prem deployments where Entra isn't available, the API exposes POST /v1/auth/local. It accepts a UPN+password pair from SYNAPTORY_CP_LOCAL_*_PASSWORD env vars and mints the same SYNAPTORY1 token format.
| Flag | Container | Default | Purpose |
|---|---|---|---|
SYNAPTORY_CP_LOCAL_AUTH_ENABLED | api | false | Enables POST /v1/auth/local |
SYNAPTORY_LOCAL_AUTH_ENABLED | web | false | Renders the password form on /auth/login |
Both must be true for the flow to work end-to-end. The admin slot grants [synaptory-users, synaptory-admins]; the user slot grants [synaptory-users] only. Tokens minted via local-auth carry the same upn claim format and are indistinguishable from Entra-minted tokens once issued — the server treats them identically.
Never enable in deployments expected to use Entra. It's a back-door by design, intended for dev fixtures and disconnected on-prem.
Watermarking and IP delivery
Identity also determines watermarking. Every skill-body fetch (GET /v1/skills/<name>) is watermarked per-UPN before delivery:
- Visible HTML comment — the first line of every body is
<!-- synaptory-id: {sha256-prefix} -->. Explicit deterrent; easily stripped. - Steganographic zero-width Unicode pattern — inserted at positions seeded by a deterministic RNG keyed on the watermark hash. Survives comment stripping. Reproducible per-user on every fetch.
The watermarker lives at api/synaptory_api/watermark.py and is applied by api/synaptory_api/routers/skills.py. See ADR-016 for the IP-delivery model.
What's next
- Auth flows reference — sequence diagrams for each path.
- Permissions reference — what each group + project role can do.
- Personas — how identity maps to who-touches-what.
Personas
Synaptory serves several roles. A person may hold more than one, but authority follows the action being performed rather than the person's informal title.
Delivery user
You are: a developer, product owner, technical lead, or delivery manager running governed work inside Claude Code, Codex, or Cursor.
You use: the host entry point, .synaptory.yaml, the synaptory CLI, and the Cycle/attempt views in the Control Plane.
Start with:
Gate approver
You are: the human accountable for the admitted set at Commit, a cut, the Checkpoint close, or an Acceptance.
You decide: whether the proposed scope/outcome is acceptable given the displayed evidence, exceptions, dependencies, and residual risk.
You do not delegate: the approval itself to a host agent or runtime. Automation may prepare the decision package, but it cannot approve on your behalf.
Start with: SPQ Cycle Model and Release.
Project administrator
You are: responsible for project membership, policy, trackers, runtime eligibility, and delivery visibility.
You use: /projects, /policy, /cycles, /attempts, and the analytics/audit pages available to your role.
Start with: Configuration, Inviting Users, and Using the Control Plane.
Runner operator
You are: responsible for machines that execute local or managed runtime profiles.
You verify: runtime installation/version, credential scope, registration, leases, fencing, budgets, cancellation delivery, and teardown.
Useful commands:
synaptory runtimes list
synaptory runtimes doctor
synaptory runtimes register
synaptory runtime explain --attempt <id>
Start with: Hosts and Runtimes and Troubleshooting.
Global administrator
You are: responsible for the Synaptory service across projects.
You own: tenant-wide access, policy publication, system health, pricing, backups, audit, runner supervision, and incident response.
You do not use delivery authority to bypass: project membership, evidence gates, or human approvals.
Start with: the operator documentation in the repository module READMEs and Architecture.
Synaptory maintainer
You are: changing the host distributions, CLI, API, web application, lifecycle kernel, runtime adapters, or infrastructure.
You preserve: cross-host semantic parity, fail-closed capability behavior, versioned contracts, append-only state, and accurate user documentation.
You use: the source repository and maintainer-only ./synaptory build/release script. Those commands are not part of the consuming-project interface.
Start with: the relevant module README, architecture decisions, and the generated-doc build/tests.
Legacy project owner
You are: responsible for an existing Scrum or Kanban compatibility project.
Recommended path: finish a safely bounded in-flight unit if necessary, preserve historical state, and start new governed work as SPQ. Do not enable runtime federation on the legacy lifecycle.
Start with: Migrate to SPQ.
The SPQ Delivery Lifecycle
SPQ is Synaptory's primary lifecycle for new and continuing delivery. It makes scope, role dispatch, evidence, integration, and human approval explicit.
Unlike a prompt-driven workflow, SPQ does not let the current conversation decide what happens next. The repository-owned lifecycle state and the shared advance kernel select the next legal action.
Lifecycle overview
Four stages. Commit, Sync and Checkpoint are recorded events alongside them, not stages of their own -- a distinction that matters because an event gates nothing.
stateDiagram-v2 [*] --> DISCOVERY DISCOVERY --> CYCLE: baseline approved CYCLE --> CYCLE: another Cycle CYCLE --> ACCEPTANCE: go-live candidate ACCEPTANCE --> CYCLE: not the final Acceptance ACCEPTANCE --> COMPLETE: final Acceptance, evidence valid, human approval COMPLETE --> [*]
COMPLETE has no outgoing transition at all, which is stronger than an empty one: there is no edge to relax, so only the final Acceptance can end the engagement.
Discovery
Discovery frames the outcome, the constraints, the source region, the dependencies and the evidence expectations. It produces the baseline every later Commit is measured against.
Discovery ends at a human baseline-approval gate, and the baseline is more than a revision: approved scope and non-scope, timeline and cost, a measured calibration sample, the architecture and current-system assessment, and the approving human decisions. A git sha plus a boolean cannot satisfy it. Agents may recommend a baseline; they cannot approve it on the user's behalf.
Commit
Commit is the event that opens one scope-defined Cycle. It:
- admits a non-empty set of ready Work Units, each declaring its path scope;
- seals the declaration -- the hash is what closes the set, so nothing joins the
Cycle afterwards;
- names exactly one owning Work Unit for every shared path;
- publishes the barrier criteria in advance, so the Cycle sizes against them
rather than discovering them at close; and
- records dependencies and Definition of Done expectations.
A Cycle ends when its admitted scope is terminal, not when a calendar interval expires. No timer forces an unverified close: a Cycle that cannot finish cuts rather than running long.
Cycle Execution
The advance kernel repeatedly selects an exact Work Unit and role. The normal implementation path is:
Software Engineer → Quality Engineer → Code Reviewer → Work Unit DoD
Conditional or recovery actions may select the Project Owner, Solution Architect, Compliance Engineer, Platform Engineer, Technical Writer, or Research Advisor. The orchestrator must use the selected action and may not replace it with a role chosen from memory.
Each dispatch carries an execution envelope and unique dispatch identity. The receipt must be written to the exact requested location, validate against the contract, and bind to the active dispatch before advancement is legal.
The barrier
The all-or-nothing integration barrier runs at Checkpoint, over the admitted set minus the recorded cuts, and it integrates the result to the shared trunk. It starts once every admitted Work Unit is done or explicitly cut.
Its criteria are published at Commit from one constant:
| Criterion | Asserts |
|---|---|
admitted_set_closed | the set the barrier ranges over is the one Commit fixed |
path_scopes_disjoint | no two units in a concurrent set claim intersecting paths |
shared_paths_owned | every shared path has exactly one owning Work Unit |
criteria_all_returned | every criterion actually returned a result |
acceptance_criteria_met | each retained unit met the criteria it was admitted with |
regression_green | the combined result has no regression |
trunk_integrated | the result reached the shared trunk |
criteria_all_returned is the one worth reading twice. Without it, evaluated nothing and evaluated everything and passed are the same verdict -- and an unevaluated criterion counts as unmet, never as absent.
There is no partial admission: no per_workstream mode, no per-unit promotion, no closing the part that passed. An unresolved dependency, an unverifiable event, a superseded declaration or a failed regression blocks the Cycle, and the remedy is to fix it or to cut the work that will not make it.
If another Cycle moves the trunk while this one is ready, the candidate is rebuilt and re-verified.
Sync is not this
Sync is a separate event, and it is the change most likely to surprise a reader of the older model. It records that one Cycle waited on a result from another and how that cleared. It has zero or more occurrences, no calendar slot, and it blocks nothing at all. What blocks a Work Unit is an unsatisfied dependency; the absence of a Sync event blocks nothing. There is no Sync entry to confirm and no Sync to clear.
Checkpoint
Checkpoint is the event recording what the Cycle proved: the demonstration, the barrier verdict, the integrated trunk revision, and the cut list. It then presents the next governed decision:
- open another Cycle; or
- take the integrated revision to Acceptance.
Checkpoint is not a release, and it is not the authority: the barrier is the mechanical condition and a named human records the close. It is the increment boundary where scope, evidence and follow-up work become visible -- and no closed Cycle can publish code later.
Acceptance and Complete
Acceptance runs the release-level Quality Engineer, Compliance Engineer, Platform Engineer, Technical Writer, and Code Reviewer activities. Each must produce a valid release receipt.
Acceptance is repeatable (C-15). Each go-live compiles its own evidence package on an Acceptance identity plus the trunk digest it pinned, and delivery continues in another Cycle meanwhile.
Complete is refused when any required receipt is absent or invalid, tests fail, a critical security finding remains, Code Review is not approved, or a closed Cycle lacks a recorded green barrier verdict naming its integrated trunk revision. Only the final Acceptance closes the engagement, and whether an Acceptance is the final one is derived from outstanding commitments and a recorded handover rather than read from a flag. The final release decision is a human gate.
Two Cycles, and nothing above them
SPD-194 retires the Coordination Cycle. It was the release layer above independent child Cycles, and it existed only because integration was deferred: nothing reached the trunk until a human merged, so something downstream had to gather it.
With the barrier integrating to the shared trunk at each Checkpoint there is nothing to gather. Two Cycles run concurrently when their declared source regions do not overlap -- that is the whole condition. Each has its own Engineering Lead, Crew, cadence and Checkpoint; neither waits for the other, and no cross-Cycle check runs at admission.
Two limits follow, and both are refusals rather than conventions:
- a mutually dependent pair cannot be split across Cycles. Work that cannot
be ordered cannot be split, and the declaration refuses the split and names the one-Cycle route.
- a Cycle addresses one repository. A cross-repository declaration is
refused, and the refusal names the published-package route.
See ADR-035.
Standalone operations
Status, Doctor, Help, Debug, Explore, Review, Secure, Document, Preview, and other focused operations can run without advancing SPQ. They still respect host readiness, project boundaries, and role authority.
Legacy lifecycle status
Scrum and Kanban remain available for existing projects while retirement is planned. They use the same shared receipt and advance kernel, but they are not the recommended path for new work. Codex and Cursor explicitly treat them as uncertified delivery paths.
Do not change an active project's build_mode and then hand-edit the state to match. Follow Migrating to SPQ.
Related pages
SPQ Cycle Model
SPQ keeps three levels distinct. Older sprint vocabulary blurred them, and an earlier revision of this page described five -- a Coordination Cycle above child Cycles above Workstreams. SPD-194 retires the Workstream and the Coordination Cycle and refuses the folk term Cycle of Cycles; see ADR-035.
The three levels
flowchart TD engagement[Engagement] cycle[Cycle] unit[Work Unit] engagement --> cycle cycle --> unit
| Level | Owns | Does not own |
|---|---|---|
| Engagement | The baseline, the shared trunk, and every Acceptance | A Cycle's admitted set or its cadence |
| Cycle | Its admitted Work Units, its source region, its barrier, its Checkpoint | Any other Cycle. No Cycle inspects what another admits |
| Work Unit | Atomic implementation and proof, and its declared path scope | The Cycle's barrier or its integration |
The Cycle is the only unit of parallelism (C-01, SC-MTH-012). Two Cycles run concurrently because their declared source regions do not overlap, not because something above them coordinates them.
Four stages, three events
DISCOVERY ──► CYCLE ──► ACCEPTANCE ──► COMPLETE
▲ │
└────────────┘ a non-final go-live returns to CYCLE
Commit, Sync and Checkpoint are recorded events, never stages and never gates. That is the largest change from the older model, and the part most worth reading twice:
- Commit seals the admitted set and opens the Cycle. It blocks nothing: a
Cycle with no Commit event simply has nothing for the barrier to range over.
- Sync records that one Cycle waited on a result from another and how it
cleared. It has zero or more occurrences and blocks nothing at all. What blocks a Work Unit is an unsatisfied dependency; the absence of a Sync event blocks nothing. If you are used to waiting for Sync, stop -- there is nothing to wait for.
- Checkpoint records the demonstration, the barrier verdict, the integrated
trunk revision and the cut list. The barrier is the mechanical condition and a named human is the authority; the event is the record of both.
Cycle identity
A Cycle is scope-defined. Its sequence number is allocated within its own project and is not globally unique across clones -- two clones can each open a Cycle 7. Anything crossing a Cycle boundary uses the stable cycle_id and the declaration_hash, never a display number.
The sealed declaration fixes the admitted Work Units, the source region, the trunk, the barrier criteria and the evidence expectations. It is written twice -- a local copy and a committed one that travels through git -- and a reader consults both, because a clone that fetched the Cycle holds only the second. If the local board is on a superseded revision, dispatch stops until the Cycle is hydrated again.
Source region, not a lane
A Cycle declares the source region it may address (C-08): repository-relative directory prefixes. Overlapping regions are refused at declaration, which is what lets concurrent Cycles stay independent -- no Cycle has to inspect what another is admitting.
There is no durable Workstream and no lane pin. A Crew is the people and agents seated on one Cycle; it grants nothing and is re-seatable between Cycles without changing a single barrier admission. An Engineering Lead is named per Cycle.
SPQ never resolves anything through SYNAPTORY_ACTIVE_SPEC -- that variable belongs to the Scrum/Kanban Multi-Spec mechanism, and an SPQ project ignores it.
Work Units, and how concurrency actually works
A Work Unit is admitted at Commit and carries:
- a stable identity and a
kind; - at least one acceptance criterion;
- a declared
path_scope-- the paths it may change; - dependency edges, each with a condition;
- optionally
acceptance_cases(the authored set) andexecution_order.
path_scope is required, and concurrency is its consequence (C-07, SC-MTH-010). There is no parallelism switch to turn on:
- Two units whose declared scopes intersect are refused at Commit unless
each declares a distinct execution_order. Intersecting work may run in one Cycle -- sequentially -- but never concurrently.
- With an order declared, a second dispatch onto an intersecting scope is
refused at dispatch with scope_collision while the first holds a live attempt.
- Disjoint work proceeds with no enablement. Nothing has to be configured
for two disjoint units to run at once.
The scopes compared are the ones in the sealed declaration, never the board: the board is agent-writable, and a unit that could narrow its own recorded scope could dispatch into another unit's files.
A shared path -- one more than a single unit would otherwise touch -- names exactly one owning Work Unit. Never none, never two.
Cutting is the one valve
A Cycle that cannot finish its admitted set cuts rather than running long. A cut:
- needs an explicit reason (there is no default);
- cannot take a finished unit -- it is the valve for unfinished work;
- returns the unit to the backlog and issues a key a later Commit can name;
- never moves the approved baseline. A cut that moved it would be a
re-baseline wearing a cut's name.
The cut is a committed record beside the declaration, not a field inside it: the declaration is sealed, and a resealable commitment is not a commitment. A later Commit links the re-admission, so cut and re-admitted and cut and forgotten are different records.
The barrier's subject is the admitted set minus the recorded cuts. The count taken at Commit does not shrink -- that is the denominator the cut-rate is measured against.
Acceptance repeats
Acceptance is not terminal (C-15, SC-MTH-014). Each go-live compiles its own evidence package from records the work already produced, and delivery continues in another Cycle meanwhile. Only the final Acceptance closes the engagement and records the handover -- and whether an Acceptance is the final one is derived from outstanding commitments and a recorded handover, not read from a flag somebody could set.
Repository authority
Lifecycle state, declarations, receipts and verified events are repository-owned evidence. The Control Plane provides visibility and supervision, plus the two records that must live outside the executing agent's reach -- the source-region registry and the authority-decision store -- because a process-local lock cannot be atomic across clones.
Do not:
- edit pipeline state directly;
- hand-author receipt evidence;
- use a branch tip where an exact integrated revision is required;
- let two hosts mutate the same governed stage concurrently; or
- treat a specification document as execution state.
Related pages
Hosts and Runtimes
Synaptory supports several coding hosts and several execution runtime profiles. They solve different problems and must not be treated as synonyms.
Host versus runtime
| Concept | Meaning | Example |
|---|---|---|
| Host | The application where the user invokes Synaptory and sees lifecycle guidance. | Claude Code, Codex, Cursor |
| Runtime family | The coding-agent implementation that executes an attempt. | claude-code, codex, cursor-agent |
| Adapter profile | A certified runtime family, placement, capability, and policy combination. | codex-local-v1 |
| Placement | Where the adapter executes. | local, managed-laptop |
| Attempt | One execution of one immutable dispatch envelope. | A QE proof run for one Work Unit |
Installing a plugin selects a host. It does not automatically opt the project into runtime selection or permit a different runtime to execute a stage.
Host support matrix
| Host | Install and invoke | Certified delivery scope | Key limitations |
|---|---|---|---|
| Claude Code | H3Tech marketplace; /synaptory | Primary SPQ host with the full Claude hook adapter | Requires Claude Code 2.1.196 or newer. Organization compliance policy and contract determine regulated use. |
| Codex | Codex marketplace; $synaptory | Standard, non-regulated SPQ on Codex CLI 0.147.0 or newer | Refuses baa_enforced; four total agent threads including the parent, so five Acceptance roles run sequentially; new task required after bootstrap. |
| Cursor IDE | Staff Team marketplace; /synaptory | SPQ | Public marketplace is not used. Cursor model substitution is verified through receipts rather than trusted from configuration alone. |
| Cursor CLI/headless | Project MCP preflight or agent --plugin-dir; /synaptory | SPQ when preflight reports ready | The IDE local-plugin path is ignored. One-level agent nesting. |
Scrum and Kanban share the kernel but are uncertified on Codex and Cursor. New projects should use SPQ.
Capability profiles
Runtime policy is written against four stable capabilities. The selected delivery role projects to one of them for the bounded attempt:
| Profile | Delivery roles | Typical capability |
|---|---|---|
analyst | Research Advisor | Read, investigate, compare, explain |
planner | Project Owner, Solution Architect | Define scope, architecture, and readiness |
producer | Software Engineer, Platform Engineer, Technical Writer | Modify governed artifacts and run checks |
prover | Quality Engineer, Code Reviewer, Compliance Engineer | Verify evidence and return findings or verdicts |
Synaptory v1 still dispatches and receipts the selected delivery role. Its fixed stage/capability projection supplies the runtime selector and envelope overlay. Capability profiles grant no authority.
Available pilot profiles
The current runtime bridge exposes these profiles:
| Profile | Runtime family | Placement | Scope |
|---|---|---|---|
claude-local-v1 | Claude Code | local | analyst, planner, producer, prover |
codex-local-v1 | Codex | local | producer, prover (certified, and not selectable today: see below) |
cursor-local-readonly-v1 | Cursor Agent | local | read-only prover |
claude-managed-standard-v1 | Claude Code | managed-laptop | producer, prover on a materialized disposable workspace |
Always inspect the installed CLI rather than assuming a machine can serve a profile:
synaptory runtimes list
synaptory runtimes doctor
synaptory runtimes doctor --profile codex-local-v1
doctor distinguishes a known profile from a runtime that is actually installed, reachable, version-compatible, and eligible on that machine.
Why codex-local-v1 reports not-ready even when Codex is installed
A receipt has to record the exact model that produced it, and a stand-in is refused rather than accepted: a receipt naming codex-runtime-unattributed is evidence of nothing, and it is worse than an empty field because only the empty one is visibly missing.
Codex does not tell anyone which model ran. A whole codex exec --json run is thread.started, turn.started, one or more item.completed, and turn.completed with a usage block, and none of them carries a model. Claude Code and Cursor Agent both open with a session header that names one; Codex has no equivalent line. Every envelope the kernel mints leaves the model to policy (model_route.requested: "policy-default"), so on a governed dispatch the runtime is the only possible source, and there is none.
So doctor reports the profile not-ready with that reason, register withholds it, and a dispatch to it is refused before the runtime starts. The alternative was measured: a governed Codex attempt implemented its Work Unit, ran its tests green, and was closed as a structural failure 605 seconds later for a model it could never have produced. The refusal was right; arriving at it after the work was not.
This is a certification that cannot currently be served, not a withdrawn one. The profile stays in the table, and the day the Codex CLI states its model the declaration in cli/internal/cli/runtime_local.go changes and the profile becomes selectable again. Re-measure it yourself with:
SYNAPTORY_RUNTIME_MODEL_PROBE=1 go test ./internal/cli \
-run ModelIdentityDeclarationSurvivesALiveProbe -v
Until then, route producer and prover work to claude-local-v1 (or claude-managed-standard-v1); cursor-local-readonly-v1 is unaffected and still serves prover.
How cursor-local-readonly-v1 stays read-only
Its ceiling is the runtime's own plan mode, not a sentence in the prompt. The bridge invokes cursor-agent --mode plan, so Cursor itself refuses edits whatever the model decides to attempt; --force and --yolo, which would grant those writes back, are never passed. --trust accompanies them and grants nothing: without it Cursor stops on its workspace-trust banner and exits before the attempt starts.
One consequence is visible in the evidence. A plan-mode runtime has no file handle, so it cannot write the receipt the envelope names. It states the receipt as JSON in its final message instead, and the bridge files it at the envelope's receipt path before validation. The runtime still authors the receipt — only the delivery moves — and an attempt that states nothing receipt-shaped fails as workflow-structure rather than receiving one the bridge invented.
Where a managed attempt's receipt ends up
claude-managed-standard-v1 runs in a workspace the bridge materialized from the envelope and destroys at teardown, so a receipt left there would go with it. Before teardown the bridge files that document into your project, at the same relative path the envelope named, which is the canonical receipt path the advance gate reads. So validate_receipt and advance act on the file the attempt actually produced rather than on a digest of a file that no longer exists.
Two consequences for an operator:
- A managed attempt needs a project directory. Run the bridge from inside
the project, or pass --project-dir. Without one the attempt is refused at Prepare rather than running to completion and then having nowhere to put its evidence.
- A receipt that could not be filed fails the attempt. A blocked path, a
symlinked receipt directory or an unwritable project reports failed with workflow-structure and names the path, because a receipt nobody can open is not evidence. synaptory runtime status --attempt <id> prints the filed path for an attempt that completed.
Nothing else crosses out of the workspace: not the generated settings, not the runner's Claude configuration, not the runtime's session state, and no credential. The artifacts the receipt names stay in the workspace and survive only as digests on the attempt record, which is what keeps the placement disposable.
Enabling runtime selection
Status: not yet wired into normal dispatch. The policy below is parsed and validated, and the selector resolves against it, but no host dispatch path calls the selector today. Configuring
runtimes:therefore has no effect on an ordinary SPQ Cycle Execution run: the host dispatches through its own runtime exactly as it did before. The selector and the Runtime Bridge are reachable only through the operator commands in the next section.Do not adopt this section expecting routing behaviour. It is published so the policy shape can be reviewed and so a project can be configured ahead of the wiring, which is tracked as the dispatch-integration work in Epic #339.
Runtime selection applies only to SPQ and is inert when the section is omitted. A minimal policy is:
runtimes:
version: 1
enabled: true
allowed_profiles:
- "claude-local-v1"
- "codex-local-v1"
allowed_placements: ["local"]
preferences:
producer:
- "claude-local-v1"
prover:
- "codex-local-v1"
required_capabilities:
producer:
- "workspace.write"
- "process.test"
prover:
- "receipt.v2"
fallback:
enabled: true
max_reroutes: 2
allow_out_of_order_reroute: false
allowed_profiles is the authority ceiling. A preference or pin can reorder or narrow it but cannot add an unauthorized profile. Unknown policy versions, invalid capability keys, missing requirements, and exhausted reroutes fail closed or leave selection inert with an explanation.
Runtime Bridge commands
The CLI exposes two command families:
synaptory runtimes list
synaptory runtimes doctor [--profile <id>]
synaptory runtimes register
synaptory runtime execute --envelope <path-or->
synaptory runtime status --attempt <id>
synaptory runtime cancel --attempt <id>
synaptory runtime explain --attempt <id>
Most users use list, doctor, and the Control Plane Attempts view (/attempts). Direct execute is for an already-authorized dispatch envelope; it is not a shortcut around the SPQ selector or lifecycle kernel.
An attempt has immutable identity. Status, cancellation, progress, directives, and the final receipt attach to that attempt rather than to a mutable filename or chat session.
Managed placement
The first managed profile is Claude Code on a managed laptop. The bridge materializes the exact repository revision into a disposable workspace, injects only declared connector references and capability ceilings, launches the runtime, captures normalized progress and evidence, and disposes of the workspace.
Managed placement is not available to baa_enforced projects in the current standard profile. It also does not make every local profile available remotely; each (runtime family, placement) pair needs its own certified adapter.
Having the pinned Claude Code release installed does not make a laptop a managed runner. The managed profile is served only where the runner was deliberately configured for it, with SYNAPTORY_CLAUDE_CONFIG_DIR pointing at the isolated vendor-state directory that gives the placement its one dedicated subscription identity. A developer laptop without it probes as a local runner, so doctor reports claude-managed-standard-v1 as not ready, and neither runtimes register nor the worker advertises it there.
Compliance boundaries
- Codex: the standard Synaptory package refuses regulated projects. A host
account or contract on its own does not override that product gate.
- Cursor: HC0 requires Cursor Enterprise, a signed BAA, organization-wide
Privacy Mode lock, and an eligible model. Teams, Pro, and Start are refused; third-party MCP services are not automatically covered.
- Claude Code: follow the organization's approved Claude access path,
contract, model pins, and Synaptory policy. This guide does not make a blanket regulated-certification claim.
ZDR, BAA eligibility, and Synaptory host certification are separate questions.
Cross-host discipline
Cross-host handoff is not a product feature. Claude Code, Codex, and Cursor can read the same repository-owned state, but an active governed stage follows normal single-writer discipline. Finish or stop the active dispatch, persist its valid receipt and state, and then resume from the kernel-selected action on the chosen host.
Never copy chat history or invent a transfer receipt to make a host switch look governed.
Related pages
Operation Modes
Synaptory classifies a request, reads project state, and selects either a lifecycle action or a focused operation. You normally describe the outcome rather than memorizing commands.
SPQ lifecycle operations
On a project with explicit build_mode: spq, build and continuation requests are routed through the SPQ kernel:
| Intent | Example | Governed result |
|---|---|---|
| Start delivery | "Use SPQ to deliver account recovery" | Discovery or the current required ceremony |
| Continue | "Continue the Cycle" | The exact next ceremony, dispatch, transition, or gate |
| Inspect | "Show SPQ status" | Read-only Cycle, Work Unit, Sync, and receipt summary |
| Release | "Prepare this for Acceptance" | Acceptance only when the kernel says the project is eligible |
The orchestrator must call the state authority at each boundary. It cannot use the last chat message as permission to skip a role, transition, or human gate.
An omitted build_mode still falls through to legacy Scrum for compatibility. That is why new projects must set build_mode: spq explicitly.
Diagnostics and setup
| Mode | Trigger examples | Behavior |
|---|---|---|
| Doctor | "doctor", "check readiness", "validate config" | Read-only host, auth, configuration, lifecycle, runtime, and policy diagnostics |
| Init | "initialize this project for SPQ" | Detects the project and proposes configuration/state through the governed host flow |
| Status | "where are we?", "show Cycle status" | Compact lifecycle, Work Unit, receipt, gate, and attempt summary |
| Help | "help", "what can Synaptory do?" | Host-aware quick reference |
| Report | "report a Synaptory bug" | Gathers bounded diagnostic context for a product issue |
| Update | Automatic | Checks the installed host package and CLI version without blocking an offline run |
Doctor never repairs state by silently writing files. Init or bootstrap must show planned changes and follow the host's confirmation rules.
Focused delivery operations
These operations can run without advancing an SPQ Cycle unless the request explicitly binds them to a Work Unit dispatch:
| Mode | Typical request | Primary role |
|---|---|---|
| Debug | "Find why login returns 500" | Software Engineer with structured root-cause workflow |
| Explore | "Help me compare these designs" | Research Advisor |
| Review | "Review this branch" | Code Reviewer, read-only |
| Secure | "Run a security review" | Compliance Engineer |
| Test | "Add tests for this change" | Quality Engineer |
| Architect | "Design the event contract" | Solution Architect |
| Document | "Write the operator runbook" | Technical Writer |
| Optimize | "Investigate API latency" | Platform Engineer and Code Reviewer |
| Stabilize | "Add characterization tests before refactoring" | Quality Engineer and Code Reviewer |
| Modernize | "Plan a strangler migration" | Solution Architect and Compliance Engineer |
| Preview | "Run and smoke-test the app" | Host-native execution with project checks |
| Branch Finish | "Verify this branch before merge" | Branch-scoped quality and review workflow |
| Retro | "Analyze what this Cycle taught us" | Evidence-driven retrospective |
Focused output is not automatically SPQ completion evidence. When a focused operation is part of a governed Work Unit, it must use the kernel-selected dispatch and write the required receipt.
Work Unit assistance
A request containing a stable Work Unit, story, or ticket identifier can route to focused assistance:
- Project Owner refines outcome and acceptance expectations.
- Software Engineer implements the bounded unit.
- Quality Engineer designs or executes proof.
- Code Reviewer performs read-only adversarial review.
On an active SPQ Cycle, the kernel remains authoritative. Mentioning WU-42 does not authorize an arbitrary role or transition.
Runtime supervision is not a mode
Runtime selection and attempt supervision happen below role dispatch. Commands such as synaptory runtime status inspect an authorized attempt; they do not select the next delivery action or advance state.
The Control Plane Attempts page (/attempts) likewise observes attempts and sends governed directives without becoming another scheduler.
Legacy modes
Scrum Build/Sprint and Kanban ticket flow remain available for existing projects during planned retirement. They are not the recommended starting point, and Codex/Cursor warn that these paths are uncertified.
Use the Scrum and Kanban guides only for a project that is already on that lifecycle. For new work, use SPQ. For conversion, see Migrating to SPQ.
Routing priorities
When signals overlap, Synaptory prefers the narrowest safe interpretation:
- Current governed state and exact Work Unit identity.
- Explicit diagnostic or focused-operation intent.
- Configured lifecycle continuation.
- New SPQ outcome when
build_mode: spqis explicit. - Legacy compatibility routing only for an existing legacy project or omitted mode.
Ambiguity that would materially change scope or lifecycle must be surfaced to the user rather than guessed.
Related pages
Delivery Roles and Runtime Profiles
Synaptory v1 dispatches nine delivery roles. For runtime selection it projects each bounded role dispatch onto a stage profile and one of four capability profiles. The role remains the dispatch and receipt identity; the profile overlay lets the runtime selector choose an eligible adapter.
Neither a role nor a profile can bypass the execution envelope, receipt validator, advance kernel, or a human gate.
Runtime profile vocabulary
Capability profiles are routing and skill-composition labels:
| Capability profile | Typical work |
|---|---|
analyst | Investigate, compare, challenge, and explain |
planner | Frame scope, architecture, criteria, and readiness |
producer | Modify governed artifacts and run producing checks |
prover | Replay checks, review independently, and return findings or verdicts |
Stage profiles describe where obligations sit:
admitting, analysing, planning, producing, verifying, releasing, and operating.
Capability profiles grant no authority. Filesystem, network, tool, credential, budget, and lifecycle authority come from the dispatch envelope and project policy.
Role projection
The current bounded dispatch projection is:
| Code | Delivery role | Stage profile | Capability profile |
|---|---|---|---|
| PO | Project Owner | planning | planner |
| SA | Solution Architect | planning | planner |
| SE | Software Engineer | producing | producer |
| QE | Quality Engineer | verifying | prover |
| CR | Code Reviewer | verifying | prover |
| CE | Compliance Engineer | verifying | prover |
| PE | Platform Engineer | producing | producer |
| TW | Technical Writer | producing | producer |
| RA | Research Advisor | analysing | analyst |
Project Owner was previously called Product Manager. Older data may retain the historical value; new dispatches and receipts use project-owner.
Why roles remain separate
- Software Engineer produces the candidate; Quality Engineer proves behavior.
- Code Reviewer stays clean-context, diff-focused, and read-only.
- Compliance Engineer owns security and compliance findings rather than
folding them into general code review.
- Project Owner frames the outcome; Solution Architect owns architecture and
technical contracts.
- Platform Engineer owns infrastructure and operational readiness.
- Technical Writer traces release documentation to delivered artifacts.
- Research Advisor supplies bounded research without owning lifecycle state.
Conditional work may be skipped when its trigger is absent, but the orchestrator cannot substitute a different role for a kernel-selected action.
SPQ activity map
| SPQ state/event | Typical role activity |
|---|---|
| Discovery | PO, SA, and RA frame the outcome, the constraints, the source region, and the proposed baseline. |
| Commit | Planning work fixes ready scope and acceptance expectations before production. |
| Cycle Execution | SE produces; QE and CR verify; conditional CE, PE, or other work runs when selected. |
| Checkpoint | The barrier proves the whole admitted set and integrates it to the shared trunk; a named human records the close. |
| Checkpoint | TW records the integrated increment; a human chooses the next direction. |
| Acceptance | QE, CE, PE, TW, and CR assemble the release evidence package. |
No role, host, or runtime can approve baseline, Commit scope, Sync entry/clearance, Checkpoint direction, or release completion for the human.
Host execution
| Host | Current packaging | Important behavior |
|---|---|---|
| Claude Code | Plugin skills, agents, and native hooks | Full host-native adapter; protected bodies are Control Plane delivered. |
| Codex | Nine managed profiles installed by dry-run-first project bootstrap | Full standard non-regulated SPQ; four total live threads including parent. |
| Cursor | Composed skills/subagents, rules, hooks, and MCP | One delegation level; headless work requires MCP preflight. |
Host packaging does not change the selected role or receipt contract.
Dispatch envelope
A governed attempt receives only the context needed for its selected action:
- Cycle, declaration and Work Unit identity;
- selected role plus stage and capability profile overlay;
- allowed paths, tools, network, and credentials;
- required artifacts, checks, and Definition of Done expectations;
- budget, expiry, and runtime profile;
- exact receipt path; and
- unique attempt and dispatch identity.
Missing scope is not permission to infer a larger task. The runtime must refuse or return an actionable failure.
Receipt evidence
Receipts identify the role and record artifacts, findings, executed verification commands, Definition of Done signals, runtime attribution, and completion metadata. The validator replays supported commands and rejects a receipt that is missing, stale, failed, or bound to another dispatch.
Human decisions are recorded through the governed lifecycle operation, not invented inside an agent receipt.
Related pages
Engagement Modes
Engagement mode controls how many intermediate decisions Synaptory surfaces between mandatory gates. It does not change canonical state, evidence requirements, runtime authority, or who may approve a human decision.
Structured
structured is the default. Synaptory continues through authorized, bounded operations when the next action and evidence contract are unambiguous.
Use it when:
- the Cycle baseline and Work Units are clear;
- verification commands and evidence requirements are established; and
- you want fewer prompts between mandatory gates.
Structured still stops for baseline approval, the admitted set at Commit, any cut, the Checkpoint close, and Acceptance / completion. Sync is not among them: it records a dependency having cleared and authorizes nothing.
Interactive
interactive surfaces more intermediate choices—for example architecture tradeoffs, risk decisions, scope clarification, or recovery options—before dispatch continues.
Use it when:
- Discovery is ambiguous;
- the work has material security, compliance, or product tradeoffs;
- a recovery choice could change scope or evidence; or
- a stakeholder wants a more explicit decision trail.
Interactive mode does not turn a human into the verifier and does not let an invalid receipt advance.
Configuration
engagement_mode: "structured" # structured | interactive
Compatibility aliases may still be accepted, but new configuration should use the canonical values.
Host and model behavior
The installed host and certified adapter policy determine available models, tools, and execution limits. Engagement mode is not a model selector and is not a promise about cost. A host may implement extra decision prompts differently while preserving the same governance boundaries.
Practical use
A common pattern is:
- use Interactive during Discovery to resolve outcome and risk;
- use Structured for well-bounded Cycle Execution;
- return to Interactive when recovery could change scope or at Acceptance/Release preparation.
Changing engagement mode never retroactively approves a gate or repairs missing evidence.
Related pages
Enforcement and Safety Nets
Synaptory does not treat lifecycle and quality requirements as suggestions to a model. Host adapters, the shared advance kernel, receipt validation, Sync barriers, and human gates enforce them.
Fail-closed principle
The kernel stops when it encounters:
- an illegal lifecycle transition;
- a missing, stale, invalid, or wrongly bound receipt;
- a failed verification command;
- an unresolved dependency or stale manifest;
- a non-green Sync or release-readiness verdict;
- an ineligible runtime profile;
- a tracker or Control Plane handoff error required by policy; or
- a human gate with no explicit decision.
structured and interactive engagement modes do not turn these failures into optional warnings. They change decision visibility, not safety invariants.
State authority
At every boundary the host asks the shared lifecycle authority for the next action. The returned action can authorize an exact role dispatch, an exact transition, a ceremony, recovery, or a stop reason.
The orchestrator must not:
- select a different Work Unit or role;
- advance using chat memory;
- write pipeline state directly;
- call a host's private lifecycle module as a mutation shortcut; or
- continue after an MCP, adapter, tracker, or validation error.
Dispatch binding
Before work starts, Synaptory creates an immutable dispatch identity and exact execution envelope. The envelope limits scope and names the required receipt.
A valid-looking receipt from an earlier or concurrent dispatch is rejected. A retry gets a new dispatch identity; failed evidence is preserved or archived according to the host adapter rather than silently reused.
Receipt protocol
A receipt is a verifiable claim from one selected delivery role. Its contract includes:
- stable Work Unit, role, attempt, and dispatch identity;
- Cycle, stage/capability overlay, and adapter identity when the
execution envelope provides them;
- honest host, runtime, and model attribution;
- artifacts and findings appropriate to the role;
- executed verification commands and their results;
- Definition of Done signals; and
- completion timestamps fresh for the current stage.
Conceptual example:
{
"task": "Verify WU-42 against its authored acceptance cases",
"agent": "quality-engineer",
"backend": "codex",
"model": "codex-runtime-reported-id",
"attempt_id": "att_01J6EXAMPLE",
"dispatch_id": "1a2b3c4d5e6f708192a3b4c5d6e7f809",
"adapter_profile_id": "codex-local-v1",
"placement": "local",
"stage_profile": "verifying",
"capability_profile": "prover",
"verification_commands": [
{
"command": "npm test -- --runInBand",
"exit_code": 0,
"summary": "Acceptance suite passed"
}
],
"story_dod": {
"tests_pass": true,
"build_succeeds": true,
"no_critical_findings": true,
"code_reviewed": true,
"coverage_no_decrease": true
}
}
When a host cannot expose an exact model identifier, the receipt records an honest unattributed value rather than guessing.
Validation
Validation checks:
- Schema and required fields.
- Work Unit, selected role, attempt, and dispatch binding, plus any runtime
identity copied from the execution envelope.
- Receipt freshness relative to stage entry.
- Artifact and allowed-path expectations.
- Verification object shape and actual result.
- Role-specific findings, verification results, and Definition of Done.
- Durable, minimized Control Plane delivery when required.
Local schema validity alone is not enough when the configured policy requires the authenticated projection to reach the Control Plane or durable outbox.
Work Unit pipeline
The current compatibility state path is:
queued → in progress (SE) → testing (QE) → reviewing (CR) → done
↘ recovery / blocked ↗
At the governance layer this is producing followed by isolated proving and a clean-context review. The next transition becomes legal only after the current profile-bound receipt validates. Conditional skills/checks can insert authorized activities without changing this rule.
Evidence quality
Deterministic verification commands are re-run where the host can replay them. Review and compliance findings remain structured, role-scoped evidence. Human decisions are recorded by the lifecycle operation with the real principal and exact candidate context; an agent must not manufacture them.
Missing evidence does not become a pass. The current gate remains blocked or incomplete until the required receipt and checks validate.
Sync enforcement
A Work Unit marked done in one clone is not proof that the Cycle integrates. Sync separately requires:
- terminal admitted Work Units;
- a generated barrier verdict, never a hand-authored one;
- exact sealed heads;
- verified dependency closure;
- regression, journey, and digest evidence configured by policy;
- human confirmation before integration; and
- an explicit human clear on a green verdict.
Readiness and barrier records cannot be replaced by hand-authored JSON.
Acceptance enforcement
Acceptance requires valid QE, CE, PE, TW, and CR release receipts. Complete is refused for failed tests, critical security findings, non-approved Code Review, missing release documentation, invalid receipts, or any closed Cycle without a green Sync verdict.
A repeated Acceptance compiles its own package but takes no shortcut around child evidence.
Runtime attempt enforcement
Runtime federation does not move lifecycle authority into an adapter. The selector chooses only a profile inside the configured authority ceiling. The bridge then executes the immutable envelope and records progress, directives, status, artifacts, and receipt against one attempt identity.
Unavailable capabilities cause an explained denial or governed reroute, never silent degradation. Cancellation stops the attempt; it does not advance the Work Unit.
Data minimization
The authenticated Control Plane projection is intentionally smaller than the local receipt. It can contain identifiers, host/model/token attribution, timestamps, Cycle metadata, and Definition of Done booleans. Prompts, transcripts, artifact contents and paths, commands, summaries, and findings remain local unless a separate authorized feature explicitly says otherwise.
Host adapters
The enforcement mechanism differs by host:
- Claude Code uses its full hook graph plus shared runtime operations.
- Codex uses authenticated MCP mutation gates, managed profiles, supported
hooks, and explicit bootstrap/readiness checks.
- Cursor uses MCP advancement, host hooks, composed agents/rules, and mandatory
headless preflight where the plugin path is not automatically loaded.
Differences in hook coverage do not change the shared receipt and advancement contract.
Cross-session persistence
Lifecycle state, manifests, receipts, readiness records, attempts, and context packages survive chat sessions. On resume, the host re-reads repository state and asks the kernel for the current action.
Chat transcripts are not delivery state. A new session, host restart, context compaction, or runtime process restart must not create permission to repeat or skip work.
Related pages
What's next: Synaptory Platform
This guide describes the product in this repository (Synaptory 1.x). The next system is Synaptory Platform, specified in the sibling
synaptory-specrepository (local checkout:../synaptory-spec). This page is a pointer. It creates no requirement.
The rest of this guide is 1.x. Synaptory Platform is a greenfield rebuild, not an upgrade of this install.
Authority. synaptory-spec spec/ is the only authority for platform requirements. Start with presentations/proposal-brief.html if you are new. Catalog rows (SP-*, SC-*) oblige; this page does not restate them. Decision state lives in that repository's decision register. If this page and the spec disagree, the spec wins. Decoder for 1.x UI labels: the glossary.
A naming collision. In this repository, “v1” means the shipping predecessor. In synaptory-spec, “v1” means the platform's first release (kernel + rebuilt Code slice). This page does not call the next system “v2.0.”
This product keeps shipping
This repository is the predecessor product. It stays revenue-bearing while the platform is built.
The lifecycle policy is freeze at G3 · migrate by consent · retire when empty (SPD-150, ADR-112):
- Until platform gate G3 (one complete customer-zero Code workflow), work
here continues normally.
- From the freeze: security fixes and delivery-blocking fixes continue; new
capability lands on the platform.
- A customer moves when the platform's minimum sellable subset covers their
usage. Migration is per customer, by consent, with export from here and fresh intake there.
- This product retires when no customer remains on it.
Nothing on this page changes how you use the 1.x plugin, CLI, or Control Plane today.
What Synaptory Platform is
Synaptory Platform is H3T's multi-tenant AI-enablement and delivery platform. It turns an authorized request into a governed, owned deliverable through reusable workflows that combine deterministic code, AI agents, and human judgment — while preserving each business's method, risk appetite, commercial commitments, data boundaries, and client relationships.
Work follows one seven-stage path:
Request → Analyze → Plan → Build → Prove → Release → Operate
Disciplines plug in as slices through one public contract. Synaptory Code (software delivery) is the first slice and the engine that builds the platform itself. Synaptory Consult and Synaptory GTM follow.
The canonical hierarchy is Tenant → Client → Project → Job. The contracting customer is the tenant; the tenant's own customer is the nested client. That second boundary is load-bearing.
The platform sits above AI runtimes rather than competing with them. Coding agents answer can an agent complete this task? Synaptory answers should this work happen, under whose authority, using whose data, against which commercial commitment — and what proves the accepted result was delivered?
Implementation is four repositories, consumed as pinned published artifacts — never as a copy of this tree:
| Repository | What it builds |
|---|---|
synaptory-spec | The specification and its validators |
synaptory-infra | Shared foundation |
synaptory-foundation | Control-plane implementation |
synaptory-factory | The Code slice (Synaptory Code) |
This repository is not one of those four. It is the predecessor they replace.
Progress on the platform is gated on evidence (G0–G6), not on a calendar copied into this guide. Read document 11 in the spec for gates and increments.
What changes for a 1.x user
Greenfield describes how the platform is built. It does not mean the delivery business restarts from zero. Clients, codebases, and future work carry over as fresh Requests. Identities, sessions, receipts, projects, hook state, and this control plane do not.
| 1.x today | Where it lands on the platform |
|---|---|
| H3Tech, the delivery organization | First Tenant |
| Existing clients | Clients under that tenant — a hard isolation boundary |
| Their codebases and products | Projects under the owning client |
| In-flight and future work | Fresh Requests. Prior 1.x artifacts may be referenced as source attachments; they are re-evaluated, not inherited |
Standing separation (see spec document 11 §5 and ADR-112; do not treat this list as catalog text):
- The platform deploys clean: no runtime, identity, data, or evidence
dependency on this product.
- Predecessor identities cannot authenticate there.
- Predecessor receipts satisfy no platform criterion.
- The nine 1.x agent names survive only as documented aliases for user
education (SC-MTH-005).
Labels you already see in this Control Plane
The 1.x UI adopted some next-system nouns early so a later cut-over would not be a label rewrite. Treat them as labels on 1.x objects, not as a migration path. The objects behind them stay 1.x and will be rebuilt, not carried over.
| Where you see it | What it means today | On the platform |
|---|---|---|
| Label “Spec” instead of “Story” | Renaming only; same 1.x table | A different noun: H3T-owned reusable source definition. Not this row. |
| “Project Owner” instead of “Product Manager” | Agent rename complete in 1.x | The nine agent names are education aliases only |
| “Delivery Owner” for the human role | UI-only term | A defined authority on the platform, not this UI string |
| Overview “Gate Queue” with four gates | Three are placeholders; only Evidence/DoD has a wired backend signal | Risk-scored gates at every stage boundary, not this fixed list |
| Cost panel “11 stages” | Aggregated from existing receipt fields | Per-stage receipts on the platform spine |
| Quality panel “Evidence/DoD” | Same as 1.x DoD evaluation | Prove: independent verification of the exact candidate |
What does not carry over
| 1.x mechanism | Platform position |
|---|---|
Entra groups + SYNAPTORY1 sessions + project_members | New identity realm. Predecessor identities cannot authenticate. |
| This CLI command surface | Governed clients exist on the platform; this command set is not compatible. |
| Build-time control-plane URL stamping | A 1.x deployment detail. Platform topology is specified elsewhere. |
| The 9-agent crew and its orchestration | Replaced in the Code slice; names are aliases for education only. |
.synaptory.yaml, hooks, and the 1.x state machines | Superseded. Controls sit outside runtime prompts, plugins, and hooks. |
| Scrum / Kanban as alternative operating models | One seven-stage spine. Cycle / Commit / Checkpoint / Sync are Code method vocabulary, not a second lifecycle. |
Ideas that recur are rebuilt, not migrated: watermarked method delivery, signed hash-chained receipts, a durable outbox, signed policy bundles. Each starts a new registry. 1.x receipts may enter only as untrusted attachments with provenance.
Leftover v2 / v3 labels in this repo
Those strings are not the platform version:
- Runtime identifiers.
V3_STAGESin the API analytics router and
VALID_V3_STAGES in the receipt validator still carry an old name. They are 1.x module identifiers.
- On-disk state layout. The plugin state file has a
v2(single-spec) and
v3 (multi-spec) layout version. Unrelated to the product version.
- Teamwork REST API v3. A tracker adapter detail.
Where to read the real spec
- Repository: h3tech-ai/synaptory-spec
- Local:
../synaptory-spec - README — product in one page
- Proposal brief — twenty-minute catch-up (informative)
- 00 Executive decision brief
- 11 Repository and delivery plan — four repos, gates, predecessor sunset
- ADR-112 — freeze, migrate, retire
What's next?
- Glossary — 1.x ↔ Control Plane label map
- Using the Control Plane — where those labels show up today
- Delivery Lifecycle — the 1.x Scrum / Kanban / SPQ model this product still runs
SPQ Delivery
SPQ is the primary Synaptory delivery lifecycle. Use it for new projects, continuing product work, and maintenance that needs governed scope, evidence, and integration—not only for large multi-team programs.
DISCOVERY → CYCLE → ACCEPTANCE → COMPLETE
↑ |
+---------+ a non-final go-live returns to CYCLE
Four stages. Commit, Sync and Checkpoint are recorded events, not stages and not gates: Commit seals the admitted set and opens the Cycle, Sync records a dependency having cleared, and Checkpoint records the demonstration, the barrier verdict and the integrated trunk revision.
Before the first Cycle
Confirm:
- the host plugin and matching
synaptoryCLI are installed; synaptory whoamisucceeds;.synaptory.yamlnames the correctproject_id;build_mode: spqis explicit;- the source region names durable code areas and does not overlap another live Cycle's;
trunk_refnames the one shared branch, and the regression proof passes on it; and/synaptory doctoror$synaptoryreadiness reports no blocking failure.
See Getting Started and the SPQ Setup Runbook.
Discovery
Start with the desired outcome:
Use SPQ to deliver account recovery with auditable security events. Run
Discovery, declare the source region, and show me the proposed baseline.
Discovery frames:
- the user and business outcome;
- system constraints and risk;
- its declared path scope;
- proposed Work Units and dependency edges;
- verification and shared-component expectations; and
- whether any other Cycle is live, and whether its region overlaps.
Review the baseline. Approval must be explicit and attributed to the real human principal. If the baseline is incomplete, request changes rather than approving with an informal caveat.
Commit
Commit admits the approved Work Units and opens the Cycle. Before confirming, review:
- every Work Unit has useful acceptance expectations;
- its
path_scopenames the paths it will actually change, and no wider; - dependencies name verifiable conditions;
- no work is admitted merely because an agent already started it; and
- the Cycle scope is small enough to integrate coherently.
The resulting manifest is sealed. Changing scope later is a governed operation, not a direct JSON edit.
Cycle Execution
Ask Synaptory to continue the Cycle. At every boundary the kernel selects one of these outcomes:
- dispatch the exact next role for one Work Unit;
- validate an existing fresh receipt and advance;
- recover a blocked Work Unit with an authorized role/runtime contract;
- run a lifecycle ceremony;
- stop at a human gate; or
- report a terminal or fail-closed reason.
The current compatibility state path names Software Engineer, Quality Engineer, and Code Reviewer. Its governance meaning is producing → isolated proving → clean-context review → Definition of Done. Do not skip a selected action because the change looks small.
Receipts
Each attempt receives an exact execution envelope containing the Work Unit, allowed paths, expected artifacts, verification commands, receipt path, and dispatch identity. A receipt is accepted only when it:
- uses the selected role and honest host/runtime attribution;
- binds to the active dispatch;
- records actually executed verification commands and exit codes;
- satisfies the role-specific verification and Definition of Done contract; and
- is fresh for the current stage.
Supported verification commands are replayed, and structured review or compliance findings stay role-scoped. Human judgments are recorded through the governed lifecycle operation. A missing or invalid receipt stops advancement. Repair the evidence or repeat the governed dispatch; never copy an older receipt into place.
Dependencies
Within one Cycle the declaration refuses an edge to a unit the Cycle did not admit, and the refusal names the two legal routes: co-admit the pair, or consume a published version of the upstream at this Cycle's own Commit. Work that cannot be ordered cannot be split across Cycles.
Across concurrent Cycles the producer publishes a verifiable dependency event and the consumer refreshes its ledger before the kernel re-evaluates dispatch. Prefer the narrowest condition that makes the consumer safe -- wait for a verified contract, not for the producer's whole Cycle. When the wait clears, a Sync event records it. Nothing waits for the event itself.
An event that cannot be verified is a claim, not evidence. The default policy keeps it blocked.
The barrier, at Checkpoint
When every admitted Work Unit is terminal -- done, or explicitly cut -- the Cycle closes through its barrier. The barrier is all-or-nothing over the admitted set minus the recorded cuts (C-04), and it integrates the result to the shared trunk (C-05). There is no partial admission and no per-unit promotion.
Its criteria are published at Commit, from one constant, so the Cycle sizes against them rather than discovering them at close:
admitted_set_closed path_scopes_disjoint shared_paths_owned
criteria_all_returned acceptance_criteria_met regression_green
trunk_integrated
criteria_all_returned is not decoration. Without it, evaluated nothing and evaluated everything and passed are the same verdict.
A red barrier names the failed criterion. Repair the named evidence and re-evaluate -- and if the Cycle cannot meet its barrier, cut the work that is not going to make it rather than closing on a weaker verdict. A cut needs an explicit reason, returns the unit to the backlog, and never moves the approved baseline.
If another Cycle moves the trunk while this one is ready, the candidate is rebuilt and re-verified. A green result against a trunk revision that has moved is green about something else.
Checkpoint
Checkpoint captures the integrated increment, Technical Writer evidence, Cycle metrics, and follow-up decisions. Choose one:
- Continue: return to Commit with the next approved scope.
- Accept: move the accumulated release candidate to Acceptance.
Checkpoint is also the natural place to stop a working session. Repository state and receipts—not the chat transcript—allow the next session to resume.
Acceptance
Acceptance dispatches five release activities:
- Quality Engineer—full release verification.
- Compliance Engineer—security and compliance evidence.
- Platform Engineer—deployment and operational readiness.
- Technical Writer—release documentation and runbooks.
- Code Reviewer—final read-only release review.
Hosts may execute these sequentially even when the activities are logically independent. In particular, the certified Codex path has a four-thread total limit including the parent and therefore runs all five sequentially.
Complete remains blocked until every required receipt is valid, every closed Cycle recorded a green barrier verdict naming its integrated trunk revision, and the human explicitly accepts the release. Only the final Acceptance closes the engagement -- an earlier one produces its own package and returns delivery to another Cycle.
Runtime-supervised attempts
When an SPQ runtimes: policy is enabled, the selected role projects to a capability profile that maps to an eligible adapter profile. The lifecycle authority does not move into the runtime bridge: attempts execute envelopes and return evidence; only the advance kernel changes delivery state.
Use synaptory runtime status --attempt <id> or the Control Plane Attempts page (/attempts) for long-running attempts. Cancellation stops the attempt but does not mark its Work Unit complete.
Common stop reasons
| Reason | Response |
|---|---|
| Missing or stale receipt | Re-run the authorized role dispatch and produce a fresh dispatch-bound receipt. |
| Declaration superseded | Re-hydrate through the governed host action before dispatching. A board on a superseded revision is executing an easier admitted set. |
scope_collision | Another Work Unit holds a live dispatch on an intersecting declared path scope. Finish or release it; intersecting work runs sequentially. |
| Dependency ledger stale | Refresh once; if still unresolved, coordinate with the named producer. |
| Unverified dependency | Replace the claim with a verifiable condition or evidence. |
| Barrier regression failed | Fix the integrated result, then re-evaluate the whole set. A partial fix does not clear an all-or-nothing barrier. |
| Runtime profile ineligible | Use runtimes doctor and runtime explain; do not silently substitute. |
| Human gate | Present the evidence and wait for the real user's decision. |
Related pages
SPQ Setup Runbook
Use this runbook to prepare the repository, the source region, the trunk and the tracker before the first SPQ Commit. Lifecycle mutations go through the installed host adapter; the commands below are normal Git and diagnostic operations only.
This runbook changed shape at
SPD-194. The previous version had you provision one clone per Workstream plus an integration clone, commit three Sync proof scripts, and track a readiness record per lane. The Workstream and the Coordination Cycle are retired, the barrier moved from Sync to Checkpoint where it integrates to the shared trunk, andsync-regression.sh/shared-digest.share deleted. One clone is the normal case. See ADR-035.
1. Confirm the host
Complete Getting Started and run the host's Doctor flow. The project must have:
- a matching host plugin and
synaptoryCLI; - an authenticated user and a valid
project_id; - explicit
build_mode: spq; - a host certified for the intended project class; and
- no active legacy dispatch that would overlap initialization.
Codex standard SPQ refuses regulated projects. Cursor regulated use requires the Enterprise conditions in Hosts and Runtimes.
2. Choose the source region
This is the input codebase detection cannot decide safely, and it is now the only topology decision.
A source region is the set of repository-relative paths a Cycle may address (C-08). It is declared per Cycle and sealed with it.
| Decision | Why it matters |
|---|---|
| Region paths | Two Cycles may run concurrently only if their regions do not overlap. Overlapping regions are refused at declaration |
| Trunk ref | The one shared branch the Cycle integrates into at Checkpoint. A Cycle that closes having integrated nothing anyone else can see has not closed |
| Repository | Exactly one per Cycle (C-10). A cross-repository declaration is refused, and the refusal names the published-package route |
Name product or code areas, not people, teams or runtimes. There is no shared owner to nominate at the project level and no integration seat: a shared path -- one that more than a single Work Unit would touch -- names exactly one owning Work Unit in the declaration, decided per Cycle.
build_mode: "spq"
spq:
source_region:
- "api/"
- "web/"
trunk_ref: "refs/heads/dev"
There is no parallelism switch and no isolation mode. Concurrency is a consequence of the path_scope each Work Unit declares:
- intersecting scopes are refused at Commit unless each declares a distinct
execution_order -- they then run sequentially in one Cycle;
- a concurrent dispatch onto an intersecting scope is refused with
scope_collision;
- disjoint work proceeds with nothing to enable.
See Configuration for the full key list.
3. Prepare the regression proof
The barrier publishes its criteria at Commit, from one constant, and regression_green is one of them. Commit the script that proves it and run it manually once on the trunk before opening the first Cycle -- a proof command that has never succeeded outside the barrier is setup debt, not evidence.
The three-script Sync arrangement is gone with the Sync barrier. There is no shared-digest step: shared-path ownership is declared per Cycle and checked against the declaration rather than recomputed from a digest on two sides.
4. One clone is the normal case
Open Discovery and Commit in your working clone. Commit allocates the stable cycle_id and seals the declaration; do not invent matching branch names independently.
A second clone is for a second concurrent Cycle with a disjoint source region, not for a lane inside one Cycle. In that clone, ask Synaptory to hydrate the sealed Cycle. Hydration verifies the seal before adopting anything and projects the whole admitted set -- there is no slice of the board to take.
SYNAPTORY_ACTIVE_SPEC is a legacy Scrum/Kanban Multi-Spec variable and an SPQ project ignores it.
5. Configure committed SPQ paths
Two things must be visible across clones: the sealed declaration and the cut record. Other local runtime state stays ignored.
.synaptory/*
!.synaptory/cycles/
The first rule must use .synaptory/*, not .synaptory/. Git cannot re-include a child of a directory that was excluded as a whole.
.synaptory/cycles/<cycle-id>/ holds manifest.json (the sealed declaration), cuts.json (the recorded cuts) and events/ (verified dependency events). The cut record is committed for a specific reason: the barrier's subject is the admitted set minus recorded cuts, and the barrier can run in a clone that did not make the cut.
.synaptory/sync/ is gone, and so is the boundary guard that protected it.
Before Commit, verify the paths can be tracked:
git check-ignore -v .synaptory/cycles/example.json
open_cycle refuses to seal a Cycle whose committed transport is gitignored, so a misconfigured .gitignore fails at Commit rather than at the barrier. Remove the example file after the diagnostic.
6. Configure the tracker
The local, GitHub, Jira, Teamwork and Linear adapters can all serve SPQ. The tracker reflects Work Units and Cycle association; it does not become lifecycle authority.
For Linear:
- enable Cycles on the team;
- prefer
manage_cycles: falseso Synaptory binds to the team's existing cadence; - create an
Awaiting Acceptancestate when the workflow needs it.
If two concurrent Cycles run at different cadences, do not force their tracker Cycle numbers to match. Cycle sequence numbers are per-project and collide by design -- anything crossing a Cycle boundary uses the stable cycle_id and the declaration_hash.
7. Dependencies, and when Sync appears
A depends_on edge names a unit and a condition. Within one Cycle the declaration refuses an edge to a unit the Cycle did not admit, and the refusal names the two legal routes: co-admit the pair to one Cycle, or consume a published version of the upstream at this Cycle's own Commit.
Across concurrent Cycles, a consumer waits on the dependency fact, not on a ceremony. When it clears, a Sync event records which Cycle waited on what, from where, and how it resolved. Sync authorizes nothing and blocks nothing -- there is no Sync entry to confirm and no Sync to clear.
An unverified claim never unblocks downstream work, and there is no toggle. That has a real cost -- a plain-string depends_on becomes usable only for board state, and the author must name a condition the consumer can check -- and it is the only way "an upstream event safely unblocks downstream work" is true rather than aspirational. A spq.sync.accept_unverified_events key was documented for a while and never read by anything; it is gone rather than wired, because wiring it would have added a documented route to weaken an evidence gate.
8. Open a small first Cycle
Ask Synaptory to run Discovery and present the baseline. Baseline approval needs a measured calibration sample, not a sha and a boolean. After approval, open a small Cycle that exercises the regression proof without carrying release-critical scope.
During the pilot, verify:
- Work Unit receipts bind to the active dispatch;
- receipts land under
spq/cycles/<cycle-id>/receipts, never a spec slot; - two disjoint Work Units dispatch concurrently with nothing enabled;
- two intersecting ones are refused at Commit without an
execution_order, and
the second is refused at dispatch with scope_collision when they have one;
- a deliberately failing proof blocks the whole barrier, not part of it;
- a cut records its reason and a backlog return, and does not move the baseline;
- the green path integrates to the trunk, reaches Checkpoint, and resumes in a
new session.
9. Add runtime selection separately
Do not combine lifecycle cutover and runtime federation unless both changes have independent acceptance evidence. First prove native-host SPQ. Then:
synaptory runtimes list
synaptory runtimes doctor
Add an explicit runtimes: policy only after the allowed profiles, placements, capability requirements and fallback behaviour have been reviewed.
Setup completion checklist
- [ ] Host Doctor is green for SPQ.
- [ ]
build_mode: spqis explicit. - [ ] The source region names durable code areas and does not overlap another live Cycle's.
- [ ]
trunk_refnames the one shared branch, and it exists. - [ ] The regression proof is committed and passes manually on the trunk.
- [ ]
.synaptory/cycles/is not hidden by.gitignore. - [ ] Tracker mappings preserve native SPQ identity.
- [ ] The first baseline is human-approved, with a measured calibration sample.
- [ ] The first small Cycle integrates to the trunk and reaches Checkpoint.
Related pages
Resuming SPQ Pipelines
SPQ resumes from repository-owned state and evidence, not from the previous chat transcript. A new session should ask the kernel for the current action before dispatching or changing anything.
What persists
Depending on the active stage, the project can persist:
- lifecycle and Work Unit state;
- the sealed Cycle declaration and the recorded cuts;
- native Cycle identity;
- dispatch-bound receipts;
- readiness records, dependency events, and Sync verdicts;
- context packages and Checkpoint reports;
- runtime attempt records and durable progress; and
- tracker identifiers and status projections.
The exact paths are implementation details of the governed runtime. Never reconstruct them from memory or treat last-session.md as more authoritative than current state.
Normal resume
- Open the clone the Cycle was opened or hydrated in.
- Confirm there is no still-running writer for the same governed dispatch.
- Verify CLI identity with
synaptory whoami. - Invoke
/synaptory statuson Claude Code/Cursor or$synaptorywith a status request on Codex. - Review the Cycle, Work Unit, stage, receipt, dependency and human-gate summary.
- Ask Synaptory to continue and follow the exact returned action.
Do not begin by asking a role to "finish what we were doing." That prompt can repeat already-receipted work or skip a gate.
Resume at a human gate
Human gates remain pending across sessions. On resume, Synaptory should present the evidence and ask for the missing decision again.
| Gate | Confirm before approval |
|---|---|
| Baseline | Discovery output, scope and non-scope, constraints, source region, measured calibration sample, proof expectations |
| Cut | An explicit reason, a backlog return, and the baseline unchanged |
| Clear Sync | Human merge complete and barrier verdict green |
| Acceptance | All release receipts valid and included scope correct |
| Acceptance | The evidence package is complete for the trunk revision it pinned |
A user identity from an old transcript is not approval. The current real principal must make the decision.
Resume a runtime attempt
An authorized attempt can continue independently of the host chat. Inspect it with:
synaptory runtime status --attempt <id>
synaptory runtime explain --attempt <id>
The Control Plane Attempts page (/attempts) shows the same attempt timeline when its projection is available.
- If the attempt is still running, do not dispatch the same stage again.
- If it completed, let the host validate the exact receipt and ask the kernel for the next action.
- If it failed, use the returned recovery/redispatch contract.
- If it was cancelled, remember that cancellation does not complete or advance the Work Unit.
Resume after context compaction
Host adapters re-anchor critical state around compaction where Synaptory supports it. Even so, the safe sequence is unchanged: read status, ask for the current action, validate any existing receipt, then continue.
Do not rely on the compacted summary for dispatch identity, allowed paths, or human approval.
Resume on another host
Cross-host handoff is not a product feature. A different host can read the same repository only under normal single-writer discipline:
- Stop or finish the active dispatch on the original host.
- Persist and validate its receipt or preserve the fail-closed status.
- Commit/push only the repository evidence that policy requires.
- Open the correct clone on the new host and run its readiness/Doctor flow.
- Ask the kernel for the current action.
Do not copy chat history, hand-author a transfer receipt, or let both hosts mutate one active stage concurrently.
Resume after plugin or CLI update
Reload or restart the host after a plugin update. Confirm the host plugin and CLI versions are compatible, then run Doctor before continuing a governed stage.
Codex profile/bootstrap changes require a new task for discovery. Cursor IDE requires Reload Window. Cursor headless requires the MCP preflight again.
An update does not permit state migration to happen implicitly. Follow any reported migration plan and re-run Doctor.
Superseded declaration or unresolved Cycle identity
If status reports a superseded declaration or no resolvable Cycle identity, ask Synaptory to hydrate the current sealed Cycle. Hydration verifies the seal before adopting anything and projects the whole admitted set -- there is no slice of the board to take. Do not copy a pin from another clone or substitute a branch name.
If the project still uses legacy Multi-Spec SPQ state, use the migration path in Migrating to SPQ.
Missing or invalid receipt
Do not fabricate a receipt from source changes. Inspect the reason:
- missing receipt: repeat the authorized dispatch;
- wrong dispatch: archive/preserve it and create a fresh dispatch;
- failed verification: fix the bounded work and rerun proof;
- stale timestamp: produce evidence after the current stage entry;
- invalid model/host attribution: record the honest runtime result; and
- Control Plane delivery pending: allow the durable outbox/handoff policy to complete.
State must not advance until validation succeeds.
Corrupt or unreadable state
Run Doctor and stop. Preserve the affected files for diagnosis. Do not delete or regenerate governed state merely to get a green initialization.
Report:
- host and plugin version;
- CLI version and identity status;
- the project and the clone the Cycle was hydrated in;
- current branch and clean/dirty status;
- Doctor reason code; and
- the last known valid Cycle/dispatch identity without pasting secrets or full transcripts.
Use an operator-reviewed recovery plan for material state repair.
Good stopping points
Prefer to stop:
- after a valid Work Unit transition;
- while explicitly waiting for a human gate;
- after a green Checkpoint; or
- after an attempt has a stable terminal status.
Avoid stopping halfway through an unrecorded human merge or while two clones can both believe they own the same stage.
Legacy pipelines
Existing Scrum/Kanban state can still resume through the shared kernel during the support period, with host certification warnings where applicable. Do not use legacy internal Python commands as a general recovery interface. Plan an SPQ migration at a stable lifecycle boundary.
Related pages
Using the Control Plane
The Control Plane at https://synaptory.h3t.co/ provides project-scoped visibility into SPQ Cycles, Acceptances, runtime attempts, quality, cost, reliability, sessions, skills, and audit activity.
It complements repository-owned lifecycle state. It does not select the next role, mutate a Cycle merely because a page was opened, or replace Git evidence.
Sign in and scope
Open the Control Plane and sign in with the same organization identity used by the synaptory CLI. The root redirects administrators to /overview and other authenticated users to /home.
Visibility is enforced by global and per-project roles:
- Global administrator: organization-wide operational and policy views.
- Project administrator: project analytics and member administration for projects they administer.
- Project member: permitted project views, with sensitive data scoped by policy.
- No project role: identity, access-request, and permitted personal surfaces only.
Requests for a project the caller cannot see return a non-disclosing response.
Most delivery pages accept ?project=<slug>. The project picker carries that scope through sidebar navigation.
SPQ pages
Cycles — /cycles
Cycles lists repository-reported SPQ Cycle telemetry. The summary and detail views can show:
- stable Cycle identity and project;
- sealed manifest and admitted Work Units;
- the declared source region;
- closure difference between admitted and terminal scope;
- the barrier verdict and the integrated trunk revision; and
- links from runtime attempts bound to the Cycle.
Cycle identity is scope-defined, not a time-window metric. The page therefore does not pretend that "Cycles in the last seven days" is the lifecycle model.
Acceptances
/coordination-cycles is gone with the Coordination Cycle. Acceptance is repeatable and each one stands on its own, so the page reports Acceptances rather than a composed parent:
- the Acceptance identity and the integrated trunk revision it pinned;
- the Cycles whose work that revision contains;
- the release-role evidence and which pieces are still outstanding;
- whether this Acceptance was the final one -- derived from outstanding
commitments and a recorded handover, not from a flag; and
- the named human who recorded the decision.
The page reports what was delivered to it. It does not dispatch into a Cycle and it is not a second lifecycle authority.
Attempts — /attempts
Attempts lists coordinated runtime attempts newest first. Local host-native dispatches may remain visible only in the host; an attempt appears here after it is coordinated through the Control Plane.
The attempt detail can show:
- attempt, project, Cycle, Work Unit, role, and runtime-profile binding;
- placement, worker/lease status, and terminal outcome;
- budget consumption;
- typed progress events and tool activity;
- a live event stream where available; and
- links back to the bound Cycle.
Lease and fencing state protect against a stale worker completing reassigned work. A stale fencing response is a safety refusal, not a retryable UI glitch.
Some supervision write controls can be unavailable on a deployed Control Plane or for a caller without the needed access. The UI must state that nothing was sent. When that happens, cancel the runtime where it is running and let the normal attempt reconciliation record the outcome.
Operational pages
| Path | Purpose |
|---|---|
/home | Identity and project-aware starting point |
/overview | Administrator KPIs, gate queue, and recent activity |
/projects | Visible projects and project administration |
/activity | Scoped delivery activity |
/quality | Receipt and Definition-of-Done evidence |
/cost | Token/model cost projections from reported usage |
/reliability | Runtime latency, errors, and delivery health |
/audit | Scope-aware audit log |
/sessions | Active sessions and revocation controls |
/skills | Skill manifest and permitted usage information |
/people | Scoped participant activity and access patterns |
/policy | Signed policy/configuration view for administrators |
/system | Service health and deployed versions for administrators |
/profile | Identity, groups, and sign-out controls |
The exact sidebar is role-aware. Not seeing an administrator page is expected when the current identity lacks that role.
Quality evidence
The Quality page projects receipt and Definition-of-Done signals. Use it to identify failing proof, missing role evidence, or systematic quality drift.
The repository receipt remains the detailed local source. The Control Plane receives a minimized projection rather than prompts, transcripts, artifact contents, commands, summaries, or findings by default.
Cost and attribution
Cost views depend on honest host/model/token attribution delivered with receipts and attempts. An unattributed model value is preferable to a guessed model ID. Missing telemetry should appear as missing data rather than be silently estimated as proof.
Runtime federation makes attempt identity especially important: one Work Unit can have several attempts after a denial, reroute, retry, or recovery, and the page must not collapse them into one mutable row.
Sessions and revocation
The Sessions page shows sessions visible to the caller and supports scoped revocation. Revoking a session does not rewrite repository lifecycle state. A running attempt may fail its next authenticated operation and remain incomplete until reconciled.
After revocation, sign in again with synaptory login, run host Doctor, and ask the kernel for the current action before resuming.
State authority
Use this rule when the browser and a local clone seem inconsistent:
- Read the current repository state and exact manifest/receipt identity.
- Run host status/Doctor.
- Check whether the required projection is still queued in the durable outbox.
- Treat the Control Plane as stale visibility until the authenticated handoff succeeds.
Never edit local state to make a dashboard row look current.
Related pages
Release and Acceptance
In SPQ, release readiness is proven through Acceptance. When several delivery continues after a go-live, Acceptance repeats: each one compiles its own readiness above the child evidence.
When Acceptance becomes available
At Checkpoint, the delivery lead chooses either another Commit or Acceptance. The kernel allows Acceptance only when:
- admitted Work Units are terminal;
- required Cycle receipts are valid;
- every closed Cycle recorded a green barrier verdict naming its integrated trunk revision;
- no blocking dependency or recovery remains; and
- the selected release scope is coherent.
Do not trigger release merely because a branch looks complete. Ask Synaptory for the current action and use the evidence it presents.
Acceptance roles
| Role | Release evidence |
|---|---|
| Quality Engineer | Full regression, acceptance expectations, critical journeys, quality verdict |
| Compliance Engineer | Security, privacy, dependency, regulatory, and critical-finding verdict |
| Platform Engineer | Build, deployment, rollback, infrastructure, monitoring, and operational readiness |
| Technical Writer | Release notes, runbooks, API/developer documentation, known limitations |
| Code Reviewer | Read-only final review of scope, architecture, quality, and unresolved findings |
Each role receives its own release dispatch and writes its own bound receipt. One role's green result cannot substitute for another's missing evidence.
Host execution
Hosts can schedule the logically independent Acceptance activities differently. Codex runs all five sequentially because its certified configuration permits four total agent threads including the parent. Sequential execution does not weaken the required evidence.
Runtime federation does not participate in a normal release: no host dispatch path calls the selector yet, so release activities run on the host's own runtime regardless of any runtimes: policy. When an attempt is driven explicitly through the bridge, its failure or cancellation leaves the release activity incomplete.
Readiness review
Before the human decision, review:
- the exact Cycle and Work Unit scope included;
- all release receipts and verification outcomes;
- the barrier verdict and integrated trunk revision for every included Cycle;
- known limitations and explicitly accepted risks;
- deployment and rollback instructions;
- unresolved non-blocking findings; and
- runtime/model attribution required by organizational policy.
Critical test, security, review or barrier failures block Complete. The remedy is new governed evidence after repair, not an edited verdict.
Human completion gate
The real delivery lead explicitly approves or rejects completion. Synaptory records the real principal as approver. Agents cannot infer approval from phrases such as "looks good" in an unrelated context or reuse a prior release decision.
After approval, Complete is terminal for that SPQ release state. Start new work through a new governed outcome/Cycle, not by reopening terminal receipt files.
Release when several Cycles are live
There is no layer above the Cycle that composes a release, and that is the change SPD-194 made. A Coordination Cycle used to pin each child's SHA and evaluate six composition criteria; it existed only because integration was deferred -- nothing reached the trunk until a human merged, so something downstream had to gather it.
With the barrier integrating to the shared trunk at each Checkpoint, there is nothing left to gather. Each Cycle reaches the trunk on its own Checkpoint, and an Acceptance releases a trunk revision, not a set of pinned branch heads.
So when several Cycles are live:
- each closes and integrates independently. Neither waits for the other, and
no cross-Cycle check runs at admission.
- Acceptance pins one integrated trunk revision and compiles its package from
the records the work already produced.
- Acceptance repeats. A Cycle continuing through a go-live is normal;
only the final Acceptance closes the engagement.
If two Cycles are ready at the same moment, only the short promotion transaction serializes -- not their cadences. A trunk that moved forces the later one to rebuild and re-verify: reusing a green result against a revision that has changed is green about something else.
Deployment is still a controlled operation
Acceptance proves readiness; it does not grant agents unrestricted production access. Deployment follows repository and organizational controls such as pull request approval, protected environments, change windows, and rollback policy.
The Platform Engineer can prepare commands and evidence. The authorized human or deployment system owns merges, pushes, secrets, and production promotion.
Legacy projects
Existing Scrum and Kanban projects retain their legacy Release flow during the retirement period. Do not use that flow as the model for a new SPQ project. Plan migration at a stable boundary using Migrating to SPQ.
Related pages
Inviting Members to a Project
The end-to-end flow for granting and revoking project access.
Project membership is one piece of state with multiple write paths. This guide covers all of them so you can pick the right tool for the role you're playing.
What "membership" actually means
A row in the project_members table. Schema (simplified):
| Column | Meaning |
|---|---|
project_id | Foreign key into projects |
upn | The Entra UPN (user@h3t.co) |
role | member or admin (project-level role, not platform-level) |
added_at | Timestamp |
revoked_at | Null while active; set when revoked |
The check at api/synaptory_api/security.py check_project_membership reads this table on every project-scoped API call. There's no caching layer — revoke takes effect on the user's next request.
Three ways to grant access
1. Project admin via the Control Plane
You are: a signed-in user with role=admin on the target project (i.e. you hold the project-admin grant on project_members).
You go to: /projects/<slug> → Members tab → "Invite member" button.
You enter: a UPN. The user must already be a member of synaptory-users (you can't invite people who haven't been provisioned in Entra). The form rejects unknown UPNs with a 404.
The new member is active immediately. They'll see the project on /projects the next time they refresh.
2. Global admin via the Control Plane
You are: a member of synaptory-admins.
You go to: /projects/<slug> → Members tab.
The UI is identical to what project admins use — same <ConfirmDestructiveAction> primitive, same invite form, same backend endpoint (POST /v1/projects/<slug>/members). The only difference is that you can do this on any project, not just ones where you hold a project-admin role.
3. Operator via CLI
You are: an operator with shell access to the prod VM.
You run: ./synaptory api projects add-member <slug> <upn>.
Use this when the Control Plane is down, when you're seeding a fresh project, or in CI for test fixtures.
Revoke
Same three paths, mirrored:
| Surface | Action |
|---|---|
Members tab (/projects/<slug>) | Two-step revoke button per row. Visible to project admins on their projects, to global admins on any project. |
| CLI | ./synaptory api projects revoke <slug> <upn> |
A revoked member's revoked_at is set; the row stays in the table for audit. To re-add, an admin re-invites — a new row is created.
Promote / demote
A project admin can promote a member to admin and demote back, but only on projects they admin. Global admins can do it anywhere.
The CLI doesn't currently expose a promote command directly — use the Control Plane Members tab for promotion, or write the SQL by hand if the web app is unavailable.
What a new member sees
Within seconds of being added:
/projectslists the new project./projects/<slug>opens (Overview tab).synaptory statuson their CLI lists the project under their memberships.cdinto a directory configured for that project's slug; the plugin works.
If they were a member before, were revoked, and are now re-added: the new row is treated as a new membership. The old revoked_at row stays for audit; the new row has revoked_at=null.
What gets logged
Every grant / revoke / promote produces an audit row. View at /audit (filter by action=member.grant etc.) or query the audit_events table directly.
The audit row carries: who did it, who was affected, the project, the resulting role, and a free-text reason (if the form prompted for one — the Control Plane Members tab does; the CLI doesn't).
Common gotchas
- "User not found" — the UPN isn't in the local Entra group. Add to
synaptory-usersin Entra first, then invite to the project. - "Already a member" — there's an active row already. The form deduplicates; nothing's wrong.
- Plugin still 404s after invite — the user's CLI is using a cached SYNAPTORY1 token that pre-dates the invite, but membership is checked per-request, so this shouldn't matter. If it persists, ask the user to run
synaptory statusto force a fresh API hit. - Project archived — archived projects return 403 on every member-write. Unarchive via the Control Plane (
/projects/<slug>→ settings) first; this is global-admin only.
What's next
- Permissions reference — what
membervsadmingrants you. - Identity and access — the per-request enforcement model.
Migrating to SPQ
Scrum and Kanban projects can continue during their retirement period, but new delivery should converge on SPQ. Migration is a lifecycle transition, not a configuration-only edit.
Do not hand-edit state
Never change build_mode and then rewrite .synaptory/.orchestrator/pipeline-state.json to resemble SPQ. Do not copy legacy receipts into SPQ paths or use a specification identifier as a Cycle identity.
Use governed status, initialization, and migration operations so the resulting state has valid manifests, identities, and evidence boundaries.
1. Reach a stable legacy boundary
Before migration:
- finish or explicitly defer the active Scrum story or Kanban ticket;
- resolve in-flight agent dispatches;
- capture the current status and outstanding backlog;
- commit project work and lifecycle evidence that policy requires; and
- prefer a Sprint Close, Kanban Review, or completed release boundary.
If the current project is inconsistent, run Doctor and repair it before starting SPQ. Migration must not hide an existing state failure.
2. Inventory the future SPQ shape
Map the existing delivery structure into:
| Legacy concept | SPQ decision |
|---|---|
| Product/backlog | Project outcome and Discovery baseline |
| Sprint or ticket batch | Candidate scope for the first Cycle |
| Story/ticket | Work Unit, after readiness review |
| Component/team board | Part of a Cycle's source region when it represents a lasting code area. It is not a lane with a lifecycle of its own |
| Cross-team dependency | A verifiable depends_on edge. Within one Cycle if the pair cannot be ordered; across Cycles only against a published result |
| Release train | Repeatable Acceptance. There is no layer above the Cycle that composes releases |
Do not automatically turn every team or board into a region. Regions must survive staffing changes.
3. Separate Multi-Spec from SPQ identity
Legacy Multi-Spec uses spec-scoped Scrum/Kanban tracker and state projection. SPQ uses native Cycle identity and ignores SYNAPTORY_ACTIVE_SPEC.
If the repository has older SPQ state stored under a Multi-Spec location, ask Synaptory Doctor for the native-SPQ migration plan. The low-level migrate_spq_native.py utility is an operator recovery tool and should not be used as a general Scrum/Kanban conversion command.
4. Prepare configuration
Propose and review:
build_mode: "spq"
spq:
source_region:
- "api/"
trunk_ref: "refs/heads/dev"
Keep existing tracker configuration when supported. Remote trackers work with SPQ; their sprint/cycle terminology is an adapter concern and does not replace SPQ state.
Do not enable runtimes: during the same change unless runtime federation is a separate reviewed objective. First prove the native host path.
5. Initialize SPQ through the host
Ask Synaptory to initialize or migrate the project for SPQ and present the planned state before applying it. Codex uses its authenticated MCP lifecycle operation; Claude Code and Cursor use their governed host adapters. No host should mutate lifecycle state through copied Python commands.
After initialization, run Doctor again and confirm:
build_mode: spqis explicit;- the SPQ state is readable;
- Cycle identity is native;
- the host is certified for the intended project class; and
- no legacy active dispatch remains.
6. Run a fresh Discovery
Do not treat a legacy backlog as an already approved SPQ baseline. Discovery can reuse existing product and architecture evidence, but it must explicitly frame the first SPQ outcome, the source region, dependencies and proof expectations.
The first Commit should admit a deliberately small Cycle. Use it to validate receipt paths, the regression proof, tracker mappings and the human gate workflow.
7. Preserve legacy history
Legacy state and reports remain historical evidence. Keep them read-only and clearly labeled; do not make the first SPQ Cycle continue legacy sequence numbers merely for cosmetic continuity.
Update team runbooks and automation to stop invoking Scrum/Kanban state-machine commands or setting SYNAPTORY_ACTIVE_SPEC for SPQ work.
Rollback boundary
Before the first SPQ Commit, a failed initialization can be repaired through the governed setup flow. After Work Units are admitted, do not "roll back" by switching build_mode and editing state. Stop the Cycle, preserve evidence, and use an operator-reviewed recovery or migration plan.
Related pages
Migrate a project from hiro-crew to Synaptory
Transitional guide. hiro-crew was renamed to Synaptory. If your project repo was set up with the old plugin, run this once to convert it. The
synaptory migratecommand and the session-start nudge are temporary and will be removed in a future release after all downstream projects have migrated.
What it does
A repo that used hiro-crew has, on disk:
.hiro-crew.yaml— project config.hiro-crew/— orchestrator state (pipeline-state, receipts, specs, protocols, deliverables)CLAUDE.md/AGENTS.md—hiro-crewmarkers (<!-- hiro-crew-state … -->, fences).claude/settings.json— thehiro-crew@h3tech-aiplugin id.gitignore/.dockerignore/ docs —.hiro-crewpath references
synaptory migrate renames .hiro-crew.yaml → .synaptory.yaml, moves .hiro-crew/ → .synaptory/, and rewrites every embedded hiro-crew reference (markers, paths, plugin id, URLs, brand text) so the Synaptory plugin recognizes the project. It takes a backup first and is idempotent.
Steps
From the project root:
synaptory migrate --dry-run # preview the plan, no changes
synaptory migrate # apply (asks to confirm; --yes to skip)
A snapshot of the pre-migration state is saved to .synaptory/.migrations/<timestamp>-pre-synaptory-rename.tar.gz. Review git diff, then commit.
Then, in Claude Code, point at the Synaptory marketplace and re-authenticate:
/plugin marketplace add https://github.com/h3tech-ai/marketplace
/plugin install synaptory@h3tech-ai
synaptory login # re-authenticate against synaptory.h3t.co
Notes
- Backup + git are your safety net — the "thorough" rewrite also updates
brand prose in README/docs; check git diff and revert anything you'd rather keep verbatim.
- Multi-spec repos keep their
.synaptory/.orchestrator/specs/<id>/
isolation; tracker IDs, sprint metrics, and BAA flags are preserved.
- Re-running is safe: if
.synaptory.yamlalready exists, migrate is a no-op. - Flags:
--project-dir <path>(default: cwd),--dry-run,--yes,
--backup-dir <path>.
Legacy Scrum Delivery
Legacy compatibility path. Scrum is maintained for existing projects while retirement is planned. New projects should use
build_mode: spq. Runtime federation is not available in Scrum.
This page exists so an in-flight Scrum project can reach a safe boundary without relying on old internal-command documentation. It is not the recommended onboarding path.
When to continue temporarily
Continue the legacy lifecycle only when stopping mid-sprint would create more risk than finishing its bounded scope. Prefer to:
- finish or explicitly defer every active story;
- preserve receipts, tracker bindings, and DoD evidence;
- complete the current review/close boundary through the host adapter; and
- start subsequent delivery as a new SPQ Cycle.
Claude Code retains the compatibility path. Codex and Cursor have not certified Scrum end to end and must warn before dispatch.
Supported interaction
Use the active host entry point and natural language:
Show the current legacy Scrum state and the next governed action.
Resume the active sprint without adding new scope.
Prepare the current sprint for its safe close boundary.
Do not run internal state-machine modules or edit .synaptory/ lifecycle files. The host must re-read canonical state, enforce receipts, and stop at human decisions.
Moving to SPQ
Do not translate sprint numbers into Cycle numbers or rewrite historical receipts. Preserve the completed legacy history and initialize the next outcome as SPQ with explicit build_mode: spq.
Follow Migrate to SPQ for the boundary checklist and vocabulary mapping.
See also
Legacy Kanban Delivery
Legacy compatibility path. Kanban is maintained for existing projects while retirement is planned. New projects should use
build_mode: spq. Runtime federation is not available in Kanban.
Existing maintenance boards may continue long enough to reach a clean handoff boundary. Avoid adding a new program of work to the legacy board.
Safe compatibility use
- Finish, defer, or explicitly block the active ticket.
- Preserve its receipt, verification evidence, and tracker mapping.
- Avoid pulling broad new scope.
- Start the next coherent outcome as a bounded SPQ Cycle.
Claude Code retains the compatibility path. Codex and Cursor have not certified Kanban end to end and must warn before dispatch.
Supported interaction
Use the host entry point:
Show the current legacy Kanban state and active ticket.
Resume only the active ticket and preserve its evidence.
Prepare this board for migration to SPQ after the ticket completes.
Do not manipulate the board through private Python modules or hand-edited state. Tracker status is a projection; it does not replace canonical lifecycle state.
Moving to SPQ
A maintenance request can become one Work Unit in a small SPQ Cycle. Group related tickets only when they share one outcome and can pass the same integration/Checkpoint boundary.
Follow Migrate to SPQ rather than renaming tickets or replaying old transitions.
See also
Legacy Multi-Spec Delivery
Legacy compatibility path. The former Multi-Spec pattern is superseded by the SPQ Cycle. Do not start new Multi-Spec delivery.
The old model used parallel spec slots inside Scrum. SPQ now represents the useful distinctions directly:
| Legacy need | Current SPQ concept |
|---|---|
| Parallel product/code areas in one integrated delivery unit | One Cycle, with each Work Unit declaring its own path_scope. Disjoint scopes run concurrently with nothing to enable |
| Small governed items in each area | Work Units |
| One cross-area integration boundary | The Cycle barrier, at Checkpoint, integrating to the shared trunk |
| Several independent delivery units with different cadences | Several concurrent Cycles with non-overlapping source regions. Nothing sits above them |
| Combined shipment | Release after the relevant Cycles are accepted |
Choose the replacement
Use one Cycle when every area must integrate and pass one barrier at the same Checkpoint.
Use several concurrent Cycles when areas have independent scope, timing and Checkpoints. Their source regions must not overlap; that condition is what keeps them independent, and nothing composes them afterwards -- each reaches the trunk on its own Checkpoint.
Migration boundary
- Stop admitting new legacy spec work.
- Finish or explicitly defer active stories through the host adapter.
- Preserve historical spec IDs and receipts for audit.
- Identify durable product/code boundaries as the Cycle's source region.
- Decide whether the next outcome is one Cycle or two with disjoint regions.
- Initialize new canonical SPQ state; do not rewrite the legacy pipeline.
Follow Migrate to SPQ, then continue with SPQ Delivery.
Configuration Reference
Diataxis category: Reference -- information-oriented, for lookup.
synaptory reads its project configuration from .synaptory.yaml at the project root. This file controls delivery lifecycle, agent backends, project identity, directory mapping, tooling preferences, feature toggles, brownfield behavior, Definition of Done, and architecture settings.
The canonical schema with all supported keys, types, defaults, and valid values is maintained in: plugin-claude/skills/_shared/templates/synaptory.yaml.tmpl
Session authentication
synaptory authenticates via your organisation's Entra ID. No token files needed.
On first session start a browser tab opens to complete sign-in. The session is cached in the OS keychain and refreshed silently until it expires (typically 24 hours).
Run synaptory whoami to inspect the cached session at any time. For headless environments, run synaptory login --device once from a terminal and follow the on-screen instructions.
All skill access is scoped to your session identity. Usage is watermarked and auditable by your H3Tech operator.
Auto-configure your project
The recommended way to create .synaptory.yaml is to say "initialize my project". The orchestrator scans the project and generates a tailored config.
initialize my project
What initialization auto-detects
| Signal | Detection source |
|---|---|
| Language | package.json, go.mod, pyproject.toml, Cargo.toml, pom.xml |
| Framework | next.config.*, nest-cli.json, fastapi, gin, actix |
| Infrastructure | Dockerfile*, terraform/, k8s/, .github/workflows/ |
| Architecture | monolith, modular-monolith, microservices, monorepo |
| Project health | test density, TODO/HACK density, git depth, coverage config, documentation level |
The orchestrator shows a detection summary and asks before writing. Review the output before approving -- particularly paths.* for non-standard directory names.
Config keys
project_id
Control-plane project scope. The CLI uses this to scope auth, telemetry, and skill fetch.
Precedence: SYNAPTORY_PROJECT_ID env > this value > the single cached keychain session.
project_id: "my-project" # slug assigned by your H3Tech operator
build_mode
Delivery lifecycle for the project.
| Value | Behavior |
|---|---|
"spq" | Recommended. Scope-defined Cycle delivery: Discovery -> Commit -> Cycle Execution -> Sync -> Checkpoint -> Acceptance. Requires an spq: block. |
"scrum" | Legacy compatibility default when the key is omitted. Planned for retirement. |
"kanban" | Legacy continuous ticket flow. Planned for retirement. |
build_mode: "spq" # set explicitly for new projects
An omitted value still resolves to Scrum in the current compatibility layer. Documentation therefore calls SPQ the recommended lifecycle, not the implicit technical default. Do not leave the key unset on a new project.
engagement_mode
Controls how prominently Synaptory surfaces decisions between mandatory human gates.
| Value | Behavior |
|---|---|
"structured" | (Default) Continue autonomously between mandatory gates when the dispatch/evidence contract permits. |
"interactive" | Surface more intermediate choices for human review. Does not weaken validation or add authority. |
Aliases:
autonomousandhands-offare accepted as aliases forstructured.controlledandhands-onare accepted as aliases forinteractive. New config should use the canonical names.
engagement_mode: "structured" # structured | interactive
agents.*
Legacy compatibility section. Each host now owns its native role runtime: Claude Code uses Claude, Codex uses Codex/OpenAI models, and Cursor uses its configured model surface. Governed cross-runtime selection is configured under runtimes:, not here.
| Key | Type | Default | Description |
|---|---|---|---|
agents.default_backend | string | "claude" | Accepted for compatibility. It is not the runtime selector and non-Claude values do not create cross-runtime dispatch. |
The orchestrator runs in the installed host. Model choice follows that host's approved policy. A selected role maps through the fixed capability projection; role names are not adapter profile IDs.
The runtimes: policy does not influence this today. It is parsed and validated, but no host dispatch path consults the selector, so an ordinary Cycle Execution run is unaffected by it. See Hosts and runtimes.
agents:
default_backend: "claude"
tracker.*
Ticket tracker backend for story, epic, sprint, and backlog management.
| Key | Type | Default | Description |
|---|---|---|---|
tracker.backend | string | "local" | Backend provider: local, github, jira, teamwork, linear. local stores compact state in tracker-data.json and canonical content in ID-named Markdown files under docs/requirements/. |
tracker.github.repo | string | "" | GitHub repo (owner/repo). Auto-detected from git remote if empty. |
tracker.github.cli_command | string | "" | Command that speaks the gh argument grammar. Empty means plain gh, so tracker writes are attributed to whoever's gh auth session is on the machine. Set it to a token-broker wrapper (e.g. h3t-gh-planner) to attribute agent writes to a bot identity that holds only the permissions the backlog needs. A value set here wins over the SYNAPTORY_GITHUB_CLI environment variable, so an ambient variable cannot silently downgrade a committed identity. |
tracker.github.points_label_prefix | string | "points:" | Label prefix for story points. |
tracker.github.sprint_milestone_prefix | string | "Sprint " | Milestone naming prefix. |
tracker.jira.url | string | "" | Jira Cloud URL (e.g., https://team.atlassian.net). |
tracker.jira.project_key | string | "" | Jira project key (e.g., ANC). |
tracker.jira.board_id | int | null | Scrum board ID. Auto-detected if null. |
tracker.teamwork.site_name | string | "" | Teamwork subdomain. |
tracker.teamwork.project_id | int | 0 | Numeric project ID. |
tracker.teamwork.sprint_milestone_prefix | string | "Sprint " | Milestone naming prefix. |
tracker.teamwork.workflow_stages | object | — | Maps synaptory statuses to Teamwork board column IDs. |
tracker.linear.team_key | string | "" | Linear team key (e.g. ENG) — the short key, not the team name. Required. |
tracker.linear.team_id | string | "" | Optional team uuid. Set to skip the by-key lookup. |
tracker.linear.project_id | string | "" | Optional default Linear Project applied to created issues. |
tracker.linear.label_prefix | string | "hc:" | Prefix for the entity labels that type an issue (hc:epic, hc:story, …). Linear has no native issue-type field. |
tracker.linear.manage_cycles | bool | false | Whether Synaptory may call cycleCreate. Default false: Linear creates cycles on the team's own cadence, so create-sprint binds to an existing cycle and reports if none matches. |
tracker.linear.cycle_length_days | int | 14 | Length of a cycle Synaptory creates when manage_cycles is true and the caller supplied no dates. Linear requires both startsAt and endsAt on cycleCreate. |
The local backend works in any build_mode. Remote backends (github, jira, teamwork, linear) work with Scrum, Kanban, or SPQ. Tracker Sprint/Cycle terminology does not replace SPQ lifecycle state.
Linear specifics
Linear differs from the other remote backends in three ways worth knowing before you configure it:
- Sprints are Cycles. Linear cycles carry a native integer
number, so there is nosprint_milestone_prefixand no name parsing. Cycle numbers are team-lifetime-monotonic and never restart, so a team already at cycle 47 has no "cycle 1" for Sprint 1 to match. Binding resolves in order: an existingSPRINT-Nentry intracker-id-map.json, then a cycle whose number matches, then an explicitSprintInfo.tracker_id, then the earliest unbound, unfinished cycle — which is how a fresh Synaptory project adopts a team that is already mid-cadence. The pairing is recorded on first bind and is stable thereafter. - Epics are labels. An epic is an issue tagged
hc:epicplus itsEPIC-001id label, and a story joins that epic by carrying the sameEPIC-001label — not a parent relation and not a Linear Project. This keeps parent/child free for real sub-tasks and leaves Projects available as a multi-spec discriminator. - Statuses resolve in three tiers. Linear teams define their own WorkflowState names, so the adapter tries your
status_mapoverride, then the built-in name, then the state'stype(backlog/unstarted/started/completed/canceled). A fully custom workflow —Icebox → Up Next → Building → Peer Review → Shipped— normally needs nostatus_mapat all. Add one only when the type-based fallback picks the wrong column.
When a team has no "Awaiting Acceptance" column, AWAITING_ACCEPTANCE lands on the review state plus an awaiting-acceptance label, and read-back uses the label to tell the two apart. This matches the Teamwork behavior.
Migration —
tracker.backend: markdownwas removed. Earlier versions acceptedmarkdownas an alias forlocal. It is no longer valid: config load now fails fast with guidance. Settracker.backend: localinstead — the local backend already stores canonical content as ID-named Markdown artifacts underdocs/requirements/(with a compact JSON index), so no content moves.
tracker:
backend: github
github:
repo: myorg/my-project
specs[] — multi-spec (opt-in, since v2.7 / v2.8)
Legacy Scrum/Kanban surface. SPQ uses native Cycle identity and ignores
SYNAPTORY_ACTIVE_SPEC. Do not createspecs[]as a substitute for an SPQ source region.
When a top-level specs: block is present on a legacy project, one tracker project (local / Jira / GitHub repo / Teamwork project) hosts N partitioned backlogs. See the Legacy Multi-Spec guide for the replacement mapping.
Every remote spec carries exactly one backend binding (jira: / github: / teamwork:), matching tracker.backend. Mixed remote bindings are rejected at config-load time. For tracker.backend: local, a spec may use a local: binding or omit the backend block; Synaptory partitions local tracker state by spec id under .synaptory/.orchestrator/specs/<id>/.
| Key | Type | Description |
|---|---|---|
specs[].id | string | kebab-case spec id (used in --spec flags, directory names). |
specs[].name | string | Human-readable label for the spec. |
| Local binding | ||
specs[].local.requirements_dir | string | Optional spec-specific Markdown artifact root, e.g. docs/venue-agent/requirements. |
| Jira binding | ||
specs[].jira.url | string | Jira Cloud URL. Must agree across specs (single project). |
specs[].jira.project_key | string | Jira project key. Must agree across specs. |
specs[].jira.board_id | int | Spec's Scrum board id (one per spec). |
specs[].jira.filter.type | enum | label \ |
specs[].jira.filter.value | string | Label name, component name, epic key, or raw JQL fragment. |
| GitHub binding | ||
specs[].github.repo | string | owner/repo. Must agree across specs. |
specs[].github.sprint_milestone_prefix | string | Optional per-spec milestone prefix override. |
specs[].github.filter.type | enum | label \ |
specs[].github.filter.value | string | Label name or milestone title. |
| Teamwork binding | ||
specs[].teamwork.site_name | string | Teamwork subdomain. Must agree across specs. |
specs[].teamwork.project_id | int | Numeric Teamwork project id. Must agree across specs. |
specs[].teamwork.filter.type | enum | tag \ |
specs[].teamwork.filter.value | string | Tag name (auto-resolved to tag id) or numeric tasklist id (as string). |
When specs: is absent (default), single-spec behavior is unchanged. When specs: is present, the legacy top-level tracker.<backend> block is ignored if it agrees with every spec, and rejected if it disagrees.
# Jira example
tracker:
backend: jira
specs:
- id: "platform"
name: "Multi-tenant Platform"
jira:
url: "https://hano.atlassian.net"
project_key: "HT"
board_id: 136
filter:
type: "label"
value: "platform"
# GitHub Issues example
tracker:
backend: github
github:
repo: "h3tech-ai/example-app"
specs:
- id: "platform"
name: "Multi-tenant Platform"
github:
repo: "h3tech-ai/example-app"
filter:
type: "label"
value: "platform"
# Teamwork example
tracker:
backend: teamwork
teamwork:
site_name: "hano"
project_id: 999
specs:
- id: "platform"
name: "Multi-tenant Platform"
teamwork:
site_name: "hano"
project_id: 999
filter:
type: "tag"
value: "platform"
Do not migrate a new single-spec project into this legacy surface. Model new parallel delivery as concurrent SPQ Cycles with non-overlapping source regions, and follow Migrate to SPQ for an existing project.
spq.*
Read only when build_mode: spq.
This section changed shape at
SPD-194.spq.workstreams[], the 24spq.sync.*keys andspq.coordination.*are gone with the Workstream and the Coordination Cycle.spq.runtimesis unaffected. See ADR-035.Also gone:
spq.sync.accept_unverified_events. It was documented here and named in two refusal messages, and nothing ever read a config value into it -- the toggle was advertised and inert. Of the two ways to make that honest, this is the stricter one: an unverified claim never unblocks downstream work, and there is no setting. Wiring the key would have added a documented route to weaken an evidence gate in order to make a docs page true.
| Key | Type | Description |
|---|---|---|
spq.source_region[] | list | Repository-relative path prefixes this project's Cycles may address (C-08). Overlapping regions are refused at declaration, which is what lets two Cycles run concurrently without either inspecting what the other admits |
spq.trunk_ref | string | The one shared branch a Cycle integrates into at its Checkpoint (C-05). A Cycle that closes having integrated nothing anyone else can see has not closed |
spq.regression_script | path | Committed script proving the barrier's regression_green criterion |
spq.cycle.scope_defined | bool | Cycles end on admitted scope, not a clock. No timer may force an unverified close -- a Cycle that cannot finish cuts instead |
spq.runtimes.* | object | Retained unchanged. See runtimes.* |
spq:
source_region:
- "api/"
- "web/"
trunk_ref: "refs/heads/dev"
regression_script: "scripts/cycle-regression.sh"
cycle:
scope_defined: true
There is no parallelism switch, and its absence is the design. C-07 and SC-MTH-010 make concurrency a consequence of the path_scope each Work Unit declares, so the retired parallelism.story_parallelism and the isolation: worktree|shared distinction have no replacement key:
- intersecting scopes are refused at Commit unless each declares a distinct
execution_order; they then run sequentially in one Cycle;
- a concurrent dispatch onto an intersecting scope is refused at dispatch with
scope_collision;
- disjoint work proceeds with nothing to enable.
parallelism.max_concurrent_subagents survives as a resource ceiling. The distinction is worth keeping: a ceiling limits how much runs at once and can never make colliding work legal, while the retired switch decided whether the collision was looked for at all. Under build_mode: spq the effective policy reports that ceiling plus governed_by: "declared path scope (C-07)".
Per-Cycle rather than per-project. The declaration seals the source region, the trunk, the barrier criteria and the admitted set at Commit, so these config keys are defaults a Cycle is opened from, not the authority the barrier reads. The authority is the sealed declaration.
runtimes.*
Optional governed runtime selection for SPQ. The selector is inert when this section is absent, disabled, invalid, or used with Scrum/Kanban.
| Key | Type | Description |
|---|---|---|
runtimes.version | int | Policy schema; currently 1. Unknown versions fail closed. |
runtimes.enabled | bool | Explicit opt-in |
runtimes.allowed_profiles | list | Authority ceiling for every selection mode |
runtimes.allowed_placements | list | Permitted placements such as local or managed-laptop |
runtimes.preferences.<capability> | list | Preferred order within the allowed profiles |
runtimes.required_capabilities.<capability> | list | Required capabilities for analyst/planner/producer/prover dispatch |
runtimes.fallback.enabled | bool | Whether an ineligible preference may reroute |
runtimes.fallback.max_reroutes | int | Retry/reroute ceiling per stage |
runtimes.fallback.allow_out_of_order_reroute | bool | Whether policy can skip cheaper remediation ordering with a recorded reason |
Preferences and capability keys must use analyst, planner, producer, or prover, never a role such as se or qe.
runtimes:
version: 1
enabled: true
allowed_profiles:
- "claude-local-v1"
- "codex-local-v1"
allowed_placements: ["local"]
preferences:
producer: ["claude-local-v1"]
prover: ["codex-local-v1"]
required_capabilities:
producer: ["workspace.write", "process.test"]
prover: ["receipt.v2"]
fallback:
enabled: true
max_reroutes: 2
allow_out_of_order_reroute: false
allowed_profiles is an authority ceiling, not a claim that a machine can serve what it lists: a profile is only selected if the probe snapshot also reports it available. codex-local-v1 above is allowed and, on the current Codex CLI, never available, because Codex states no exact model id and a receipt from it would name no model. The prover preference in this example is therefore skipped and the dispatch falls through to claude-local-v1. See Hosts and Runtimes.
project.*
Project identity. Drives agent decisions for tech stack selection, scaffold structure, and execution patterns.
| Key | Type | Default | Valid values | Description |
|---|---|---|---|---|
project.name | string | "" | any | Project name used in reports and docs. |
project.language | string | "" | typescript, go, python, rust, java | Primary language. A stack hint for just-in-time tech pack retrieval. |
project.framework | string | "" | nestjs, express, fastapi, gin, actix, spring | Server framework. |
project.cloud | string | "" | aws, gcp, azure | Cloud provider. |
project.architecture | string | "" | monolith, modular-monolith, microservices | Architecture pattern. |
project.type | string | "greenfield" | greenfield, brownfield, evolved_brownfield, mixed | Project type. |
project.template | string | "" | nextjs-fullstack, express-api, python-fastapi, react-native, flutter, cli-tool, monorepo | Greenfield scaffold archetype. |
project:
name: "my-service"
language: "typescript"
framework: "nextjs"
cloud: "aws"
architecture: "modular-monolith"
type: "greenfield"
template: "nextjs-fullstack"
paths.*
Directory mapping. Critical for existing codebases with non-standard layouts.
| Key | Type | Default | Description |
|---|---|---|---|
paths.services | string | "services/" | Backend services directory. |
paths.frontend | string | "frontend/" | Frontend application directory. |
paths.tests | string | "tests/" | Test files directory. |
paths.iac | string | "infra/opentofu/" | IaC root directory. Derived from preferences.iac_tool. |
paths.ci_cd | string | ".github/workflows/" | CI/CD pipeline definitions. |
paths.docs | string | "docs/" | Documentation directory. |
paths.roadmap | string | "docs/requirements/ROADMAP.md" | Product roadmap file. |
paths.reports | string | "reports" | Sprint and pipeline reports directory. |
paths.workspace | string | ".synaptory/" | synaptory internal workspace. |
paths.brd | string | "docs/requirements/" | PO documentation output. |
preferences.*
Tooling choices. Agents respect these instead of making their own selections.
| Key | Type | Valid values | Description |
|---|---|---|---|
preferences.test_framework | string | jest, vitest, pytest, go-test, junit | Test runner. |
preferences.orm | string | prisma, drizzle, typeorm, sqlalchemy, gorm | ORM / query builder. |
preferences.ci_provider | string | github-actions, gitlab-ci, circleci | CI/CD provider. |
preferences.package_manager | string | npm, pnpm, yarn, bun | Package manager. |
preferences.linter | string | eslint, biome, ruff, golangci-lint | Linter. |
preferences.formatter | string | prettier, biome, black, gofmt | Formatter. |
preferences.frontend_framework | string | nextjs, nuxt, sveltekit, remix | Frontend meta-framework. |
preferences.state_management | string | react-query, redux, pinia, svelte-stores | Client-side state management. |
preferences.styling | string | tailwind, css-modules, styled-components, vanilla-extract | CSS / styling. |
preferences.iac_tool | string | opentofu, terraform, pulumi | Infrastructure as Code tool. Default: opentofu. |
features.*
Feature toggles.
| Key | Type | Default | Description |
|---|---|---|---|
features.frontend | bool | true | Set false for API-only projects. |
features.ai_ml | bool | false | Activates SE ai-ml mode. |
features.multi_tenancy | bool | false | Enables tenant isolation patterns. |
features.documentation_site | bool | false | Generates documentation site at Release. |
features.real_time | bool | false | WebSocket/SSE support. |
features.graphql | bool | false | GraphQL API alongside REST. |
features.grpc | bool | false | gRPC inter-service communication. |
features.event_driven | bool | false | Async messaging patterns. |
features.payment_integration | bool | false | Payment service patterns. |
brownfield.*
Settings for existing codebases.
| Key | Type | Default | Description |
|---|---|---|---|
brownfield.coverage_ratchet | bool | true | Enforce coverage-ratchet: agents must write tests before modifying untested files. |
brownfield.context_packages | bool | true | Auto-load Discover context packages into all agents. |
brownfield.characterization_tests | bool | true | Generate behavior-capturing tests during Discover. |
sprint.*
Legacy Scrum settings. Active only when build_mode: scrum; do not use them to configure an SPQ Cycle.
| Key | Type | Default | Description |
|---|---|---|---|
sprint.inception | string | "foundation" | Inception mode: foundation (just enough for Sprint 1) or blueprint (comprehensive upfront plan). |
sprint.protected_modules | list | [] | Paths the SE must confirm before touching. Supports glob strings or objects with path + reason. |
sprint.constraints | list | [] | Architectural rules prepended to every SE prompt. |
sprint.velocity | int or null | null | Average story points per sprint. Used to cap sprint scope. |
sprint.carry_over_policy | string | "move_to_next" | Incomplete story handling: move_to_next, keep_in_sprint, ask. |
sprint.require_context_injection | bool | false | SE must read existing module code before implementing. |
sprint.read_before_write | bool | false | SE must Read() every file before modifying. |
sprint.characterization_tests_first | bool | false | QE must write tests before SE touches legacy code. |
sprint:
inception: "foundation"
protected_modules:
- path: "src/modules/billing/"
reason: "Financial regression risk"
constraints:
- "Every new endpoint MUST use @CurrentTenant()"
velocity: 21
carry_over_policy: "move_to_next"
dod
Definition of Done signals used by the shared Work Unit/story pipeline. SPQ adds dispatch binding, Sync, Checkpoint, and Acceptance evidence above these checks. The sprint overlay is legacy Scrum-only configuration.
dod.story -- Per-Work-Unit/story DoD
| Key | Type | Description |
|---|---|---|
dod.story.auto_check[].id | string | Check identifier (e.g., tests-pass, build-succeeds). |
dod.story.auto_check[].description | string | Human-readable description. |
dod.story.auto_check[].critical | bool | If true, story is blocked when check fails. |
dod.story.auto_check[].agent | string | Agent responsible (optional). |
dod.story.auto_check[].adaptive | bool | If true, check scales with maturity (e.g., skip Sprint 1). |
dod.sprint -- Sprint-level overlay (Scrum only)
| Key | Type | Description |
|---|---|---|
dod.sprint.human_check[] | string | Items requiring human verification at Sprint Review. |
dod.sprint.auto_check[].id | string | Automated check identifier. |
dod.sprint.auto_check[].critical | bool | If true, sprint review is blocked when check fails. |
dod:
story:
auto_check:
- id: tests-pass
description: "All acceptance criteria tests passing"
critical: true
- id: build-succeeds
description: "Build completes and dev server starts"
critical: true
- id: no-critical-findings
description: "Zero Critical security findings"
critical: true
agent: compliance-engineer
- id: code-reviewed
description: "Story code reviewed"
critical: false
agent: code-reviewer
adaptive: true
- id: coverage-no-decrease
description: "Test coverage did not decrease"
critical: false
sprint:
human_check:
- "Sprint Goal met"
- "Stakeholder feedback addressed"
- "Documentation updated"
auto_check:
- id: no-regression
description: "No regression across sprint stories"
critical: true
dor
Definition of Ready. Used to validate stories before sprint commitment.
| Key | Type | Default | Description |
|---|---|---|---|
dor.file | string | "" | Path to a DoR markdown file. Parser reads bullet lines. |
dor.inline | list | [] | Inline DoR criteria when file is empty. |
architecture
Solution Architect settings.
| Key | Type | Default | Description |
|---|---|---|---|
architecture.health_check_interval | int | 3 | Run SA health check every N sprints (0 = disabled). |
architecture.triggers | list | [new_entity, new_service, new_integration, security_requirement, performance_story] | Auto-detect triggers for SA invocation. |
story_buddy
Story Buddy settings.
| Key | Type | Default | Description |
|---|---|---|---|
story_buddy.issue_templates | list | [] | Paths to issue template files for story structural validation. |
Complete examples
New SPQ project
version: "3.0"
project_id: "reservation-saas"
build_mode: "spq"
engagement_mode: "structured"
tracker:
backend: "github"
github:
repo: "myorg/reservation-saas"
spq:
source_region:
- "api/"
- "web/"
trunk_ref: "refs/heads/dev"
regression_script: "scripts/cycle-regression.sh"
cycle:
scope_defined: true
brownfield:
coverage_ratchet: true
context_packages: true
characterization_tests: true
Legacy greenfield SaaS (Scrum)
version: "3.0"
build_mode: "scrum"
engagement_mode: "structured"
project:
name: "reservation-saas"
language: "typescript"
framework: "nextjs"
cloud: "aws"
architecture: "modular-monolith"
type: "greenfield"
template: "nextjs-fullstack"
agents:
default_backend: "claude"
sprint:
inception: "foundation"
carry_over_policy: "move_to_next"
velocity: 21
tracker:
backend: "github"
github:
repo: "myorg/reservation-saas"
preferences:
test_framework: "vitest"
orm: "prisma"
package_manager: "pnpm"
frontend_framework: "nextjs"
styling: "tailwind"
features:
frontend: true
multi_tenancy: true
payment_integration: true
real_time: true
Legacy brownfield API (Kanban)
version: "3.0"
build_mode: "kanban"
engagement_mode: "structured"
project:
name: "payments-api"
language: "typescript"
framework: "express"
cloud: "aws"
architecture: "monolith"
type: "brownfield"
agents:
default_backend: "claude"
tracker:
backend: "jira"
jira:
url: "https://myteam.atlassian.net"
project_key: "PAY"
paths:
services: "src/"
tests: "test/"
preferences:
test_framework: "jest"
orm: "typeorm"
features:
frontend: false
brownfield:
coverage_ratchet: true
context_packages: true
characterization_tests: true
What's next?
- Commands Reference -- Host invocation, CLI, and runtime bridge commands
- Host Integration Reference -- How each host enforces the shared contract
- Getting Started -- First-time setup and configuration walkthrough
Commands Reference
Diataxis category: Reference — information-oriented, for lookup.
Synaptory has two public command surfaces:
- the host entry point used inside Claude Code, Codex, or Cursor; and
- the
synaptoryCLI used for authentication, diagnostics, policy, and runtime operations.
Lifecycle state is advanced by Synaptory through the host adapter or MCP tools. Files and Python modules under plugin hook directories are implementation details, not user commands.
Host entry points
| Host | Entry point | Notes |
|---|---|---|
| Claude Code | /synaptory | Installed from the Synaptory Claude marketplace. |
| Codex | $synaptory | Installed as a Codex plugin. Standard non-regulated SPQ requires Codex 0.147.0 or newer. |
| Cursor IDE | Start the synaptory agent or ask it naturally | Project rules, skills, subagents, hooks, and MCP configuration are installed together. |
| Cursor headless | cursor-agent with the Synaptory project configuration | Run the MCP preflight before starting governed work. |
You can follow the entry point with an operation, for example:
Start an SPQ Cycle for the account recovery feature.
Show the current Cycle and its evidence gaps.
Run Checkpoint for WU-014.
Prepare Acceptance for the current Cycle.
Resume the active Cycle.
Run Synaptory doctor.
The host interprets natural language, reads canonical state, dispatches the appropriate lifecycle agents, and pauses at required human gates. See SPQ Delivery and Routing.
Common CLI commands
Install the CLI once per machine; see Install the CLI.
Identity and health
| Command | Purpose |
|---|---|
synaptory login | Sign in through the browser. |
synaptory login --device | Sign in from a headless environment. |
synaptory logout | Revoke the cached session and clear the keychain entry. |
synaptory whoami | Show the cached identity, token expiry, and plugin version. |
synaptory status | Show authentication, cache, and outbox health. |
synaptory version | Show the installed CLI version. |
synaptory update | Check for and install an available CLI update. |
Skills and policy
| Command | Purpose |
|---|---|
synaptory skills sync | Refresh the governed skill cache. |
synaptory skills list | List cached skills. |
synaptory skills get <name> | Print one cached skill, fetching it on cache miss. |
synaptory config fetch --if-stale | Refresh the cached control-plane policy when needed. |
synaptory config env | Show the active policy summary. |
Projects, activity, and support
| Command | Purpose |
|---|---|
synaptory projects list | List visible control-plane projects. |
synaptory projects current | Resolve the current project from the workspace. |
synaptory projects show <slug-or-id> | Show project detail and membership. |
synaptory cost | Show local session token usage and estimated cost. |
synaptory activity | Inspect recorded activity. |
synaptory outbox list | Inspect queued telemetry. |
synaptory outbox flush | Retry delivery of queued telemetry. |
synaptory report submit | Submit a support report through the control plane. |
Administrative project and membership subcommands are visible only to callers with the corresponding control-plane authority. Run synaptory <command> --help for the exact flags supported by your installed version.
Runtime Bridge
Runtime federation is optional and SPQ-only. Installing Synaptory in several hosts does not enable it automatically. Configure runtimes: in .synaptory.yaml, then use these commands to inspect the effective capacity.
Machine capacity: synaptory runtimes
| Command | Purpose |
|---|---|
synaptory runtimes list | List certified adapter profiles, placements, pinned versions, capability profiles, and capability ceilings. |
synaptory runtimes doctor | Probe every configured profile and report whether this machine can serve it. An unavailable profile is reported, not hidden. |
synaptory runtimes doctor --profile <profile-id> | Probe one profile. |
synaptory runtimes register | Probe every configured profile and register this machine with the control plane, advertising only the probe-ready ones. Refuses if none are ready. |
The pilot profile IDs are:
claude-local-v1codex-local-v1cursor-local-readonly-v1claude-managed-standard-v1
register advertises what this machine can execute, not what the pilot certifies. A missing runtime binary, a version outside the profile's pin, or a machine that is not configured for the profile's placement is neither advertised nor claimable, and if nothing is ready the command refuses rather than registering an empty set (the control plane reads an empty supported_profiles as a wildcard). Because register is one-shot, its answer is a snapshot: re-run it after installing, removing, or upgrading a runtime. synaptory runtime worker is the continuous form of the same probe. It re-probes on a freshness window and re-registers whenever the ready set changes.
A profile appearing in runtimes list means the combination is recognized. It does not mean the runtime binary is installed or ready; use runtimes doctor to establish that.
One attempt: synaptory runtime
| Command | Purpose |
|---|---|
synaptory runtime execute --envelope <path> | Validate a dispatch envelope and run one attempt through its named adapter. Use --envelope - for stdin. |
synaptory runtime status --attempt <id> | Read the recorded state of one attempt. |
synaptory runtime explain --attempt <id> | Show the attempt's authority ceiling and supervision timeline. |
synaptory runtime cancel --attempt <id> --reason "…" | Request cancellation and record why. Output states whether the request reached the control plane or only the local record. |
synaptory runtime worker | Run the lease-holding worker. This is an operator surface, not a normal delivery command. |
The Runtime Bridge executes an already-authorized envelope. It does not select the runtime, expand authority, approve evidence, or advance a Work Unit. The SPQ dispatch and advance kernels retain those responsibilities.
Read-only questions vs state changes
These requests are safe lookups:
Show Synaptory status.
Which stage is the current Cycle in?
Explain attempt <id>.
What evidence is missing for WU-014?
These requests can change canonical lifecycle state and therefore run through the active host adapter, with confirmation at human gates:
Start a Cycle.
Accept this Cycle's Checkpoint on its integrated trunk revision.
Accept the current Cycle.
Release the accepted Cycle.
Cancel this runtime attempt.
Do not invoke hook scripts or lifecycle Python modules directly to force a transition. Doing so bypasses authority checks, append-only history, idempotency, and receipt validation.
Legacy commands
The CLI may expose compatibility surfaces such as specs and the transitional migrate command. synaptory migrate migrates a supported hiro-crew consumer setup; it is not the Scrum/Kanban-to-SPQ migration workflow.
For an existing Scrum or Kanban project, follow Migrate to SPQ. Keep legacy lifecycle state read-only for audit and resume new governed work as a fresh SPQ Cycle.
Maintainer-only repository script
The repository-root ./synaptory script builds and deploys Synaptory itself. It is for Synaptory maintainers, not for projects consuming the product. Run ./synaptory help from this repository for its current command surface.
What's next?
Routing Reference
Diataxis category: Reference — information-oriented, for lookup.
Synaptory routes a request in two steps: first to the configured lifecycle, then to the role or focused operation best suited to the request. Canonical project state and explicit identifiers take precedence over loose keywords.
Routing order
- Explicit operation — a request such as “run Checkpoint for WU-014” wins over inferred intent.
- Active canonical state — if a Cycle is active, Synaptory resumes the stage or gate recorded there.
- Configured lifecycle —
build_mode: spqroutes delivery work through SPQ. - Bound identifier — a Cycle, Work Unit, ticket, or attempt ID narrows scope.
- Focused intent — debug, review, security, architecture, documentation, testing, and similar operations choose a specialist role while staying bound to the active Work Unit when applicable.
- Clarification — if two materially different state-changing routes remain possible, Synaptory asks rather than guessing.
Conversation history is supporting context, not the source of truth for current lifecycle state.
SPQ lifecycle routing
| Request intent | Route | Expected result |
|---|---|---|
| “Start SPQ delivery for …” | Discovery | Establish intent, boundaries, the source region, risk, and a proposed baseline. |
| “Resume the current Cycle” | Current canonical stage/gate | Re-read state and continue the next allowed operation. |
| “Approve the baseline” | Discovery gate | Record the explicit human baseline decision. |
| “Open this Cycle” | Commit | Admit the approved non-empty set of ready Work Units and seal the manifest. |
| “Implement WU-014” | Cycle Execution / producer | Dispatch the bounded implementation attempt. |
| “Test WU-014” | Cycle Execution / prover | Dispatch verification without changing the Work Unit's authority. |
| “Close the Cycle” | Checkpoint | Run the barrier over the admitted set minus recorded cuts, integrate to the trunk, and record the close. |
| “Clear Sync” | Sync clearance | Record explicit human clearance only after the integration verdict is green. |
| “Run Checkpoint” | Checkpoint | Demonstrate the integrated Cycle and choose another Cycle or Acceptance. |
| “Prepare Acceptance” | Acceptance | Summarize outcome, evidence, exceptions, and residual risk for a human decision. |
| “Release the accepted Cycle” | Release | Run release checks and pause at the Release gate. |
Discovery, Commit, Cycle Execution, Sync, Checkpoint, Acceptance, and Complete are lifecycle states. Commit, Sync, and Checkpoint are SPQ method events mapped onto Synaptory's stage/gate spine; a request cannot skip an unmet prerequisite.
Focused operations
Focused operations may run inside an SPQ Work Unit or as bounded standalone assistance. When a Cycle is active, the result should be attached to the relevant Work Unit as evidence instead of creating a parallel lifecycle.
| Intent | Typical lead role | Examples |
|---|---|---|
| Diagnose an active failure | SE or relevant specialist | “Debug the failing login test.” |
| Review code or a diff | CR | “Review the changes for WU-014.” |
| Create or strengthen tests | QE | “Add regression tests for this Work Unit.” |
| Security or compliance assessment | CE | “Run a STRIDE review for the new endpoint.” |
| Architecture or contract design | SA | “Design the event schema for this Cycle's source region.” |
| Documentation | TW | “Document the accepted API behavior.” |
| Reliability, operations, or performance | PE, with CR as needed | “Investigate the latency regression.” |
| Research or option exploration | RA | “Compare the supported migration approaches.” |
| Project configuration/health | Orchestrator/doctor | “Validate the Synaptory setup.” |
These operations do not approve human gates and do not advance a Work Unit merely because a specialist completed.
Important tiebreakers
| Ambiguity | Resolution |
|---|---|
| Build vs debug | A concrete failure routes to debug; a new outcome routes to the active lifecycle. |
| Test vs debug | A failing behavior routes to debug; proactive coverage routes to test. |
| Review vs security | Security, audit, threat-model, OWASP, or STRIDE intent routes to compliance/security review; general code quality routes to CR. |
| Work Unit ID vs general request | The bound Work Unit wins and limits scope. |
| Release wording inside an unaccepted Cycle | Prepare Acceptance or explain the missing prerequisite; do not jump to Release. |
| Runtime preference vs policy | Policy and capability requirements win. A user preference cannot expand authority or select an uncertified profile. |
| Chat recollection vs canonical state | Canonical state wins; state is re-read before action. |
Legacy routing
Projects already configured as scrum or kanban may continue through the compatibility path, but that path is planned for retirement. New delivery work should use build_mode: spq.
Runtime federation is inert for legacy modes. If a legacy request would start substantial new work, Synaptory should recommend migrating to SPQ instead of expanding the legacy lifecycle.
Diagnosing an unexpected route
- Run
synaptory statusand ask the host to show the active canonical Cycle. - Confirm
.synaptory.yamlcontainsbuild_mode: spq. - Include the Cycle or Work Unit ID in the request.
- State the operation explicitly: Discovery, approve baseline, Commit/open Cycle, Sync entry, clear Sync, Checkpoint, or Acceptance.
- If the host cannot read canonical state or MCP tools are missing, stop and fix integration health first.
See Troubleshooting for host-specific checks.
What's next
Rules Reference
Diataxis category: Reference — information-oriented, for lookup.
Rules are host-facing guardrails, not lifecycle authority. They remind an attempt how to work safely, while the dispatch envelope, receipt validator, advance kernel, and human gates enforce what the attempt may do.
The Claude Code package currently ships eleven rule entry points in plugin-claude/rules/. Codex and Cursor express equivalent outcomes through their own instructions, skills, hooks, and MCP integration; they do not pretend to implement Claude Code's exact hook surface.
Claude Code rules at a glance
| Rule | Scope | Purpose |
|---|---|---|
synaptory-boundary-safety | Always | Prevents framework abstractions from crossing boundaries they do not own. |
synaptory-conflict-resolution | Always | Preserves single ownership when artifact responsibilities overlap. |
synaptory-flaky-tests | Tests and CI | Treats nondeterministic tests as a pipeline correctness problem. |
synaptory-freshness | .synaptory/** | Requires volatile external facts to be refreshed before use. |
synaptory-guard | .synaptory/** | Detects governed work when normal session bootstrap was unavailable. |
synaptory-loop-reactions | .synaptory/** | Maps lifecycle notifications to fail-closed recovery behavior. |
synaptory-receipt-protocol | .synaptory/** | Defines the proof-of-completion record expected from a bounded attempt. |
synaptory-secrets-scan | Secrets, environment, CI, and infrastructure paths | Prevents secret-shaped material from entering tracked artifacts. |
synaptory-ux | Always | Keeps decisions explicit, option-oriented, and attributable to the user. |
synaptory-visual-identity | Always | Keeps host output concrete, stateful, and information-dense. |
synaptory-welcome | First eligible use | Guides a new project into initialization and its first governed request. |
These names describe packaged guidance. They are not SPQ states, capability profiles, or permission grants.
Receipt rule
The receipt rule requires an attempt to verify first and record evidence afterward. For an SPQ pipeline receipt, validation binds the record to:
- the Cycle, Work Unit, attempt, and dispatch;
- the selected role and any
stage_profile/capability_profilecopied from
the runtime envelope;
- the exact artifacts and allowed paths;
- the runtime identity and execution result; and
- executed verification commands, findings, and Definition of Done signals.
A capability label confers no authority. Authority comes from the immutable dispatch envelope. Missing required evidence keeps the gate blocked or incomplete; it never becomes a pass.
Receipt filenames and role wire values remain implementation contracts. Do not invent a receipt or copy one from another attempt. Use the governed host action that created the dispatch and let validation derive the expected binding.
Loop and recovery rule
Loop reactions are deliberately fail-closed:
- a blocked Work Unit is classified before another attempt is dispatched;
- a failed criterion is remediated with evidence rather than marked complete;
- a depth or no-progress guard stops further delegation;
- state drift makes the local projection untrusted until it is re-read through
the public Synaptory surface; and
- a rejected receipt is corrected or replaced by a newly authorized attempt,
never bypassed by editing lifecycle state.
The kernel remains the only legal writer of governed lifecycle state.
Host mapping
| Governance outcome | Claude Code | Codex | Cursor |
|---|---|---|---|
| Project guidance | Plugin rules and skills | AGENTS.md, plugin skills, and agent profiles | Project rules, skills, and subagents |
| Start/stop enforcement | Native hooks | Plugin hooks plus MCP/CLI boundary | Cursor hooks plus MCP boundary |
| Governed operations | /synaptory | $synaptory | Synaptory agent or natural-language entry |
| Canonical state | Repository and advance kernel | Same | Same |
Host-native conversation state is never the delivery record. Unsupported host capabilities fail closed instead of silently weakening a rule.
Related pages
Host Integration Reference
Diataxis category: Reference — information-oriented, for lookup.
Synaptory integrates with Claude Code, Codex, and Cursor using the mechanisms each host actually provides. The hosts do not expose identical hook events, so Synaptory preserves the same governance outcomes with different adapters.
Hooks, rules, bootstrap instructions, and MCP tools are internal integration surfaces. Users normally interact through the host entry point and the public synaptory CLI.
Shared governance outcomes
Every supported host integration must preserve these invariants:
- canonical SPQ state is read before work begins;
- dispatch is bound to a Cycle, Work Unit, selected role, and
budget;
- runtime output is reduced to governed events and evidence;
- receipts are validated before a Work Unit can advance;
- human gates remain human decisions;
- retries are idempotent and append-only history is preserved;
- unsupported capabilities fail closed instead of silently weakening governance.
Host-native conversation or session state is never canonical lifecycle state.
Integration matrix
| Concern | Claude Code | Codex | Cursor |
|---|---|---|---|
| User entry | /synaptory | $synaptory | Synaptory agent / natural language |
| Project instructions | Plugin commands, skills, agents, rules | AGENTS.md, plugin skills, agents | Project rules, skills, subagents |
| Lifecycle tools | Host/plugin adapter | Synaptory MCP server | Synaptory MCP server |
| Session bootstrap | Native session hooks | Project instructions plus supported hooks/MCP bootstrap | Project rules plus supported hooks/MCP bootstrap |
| Agent completion checks | Native subagent hooks | Deterministic receipt validation through Synaptory dispatch | Agent/hook completion plus receipt validation |
| Context refresh | Native compaction/session hooks | Re-read canonical state through bootstrap and MCP | Re-read canonical state through rules, hooks, and MCP |
| Supported SPQ scope | Full | Standard non-regulated only | Full, subject to environment and policy |
| Important preflight | CLI/auth/plugin health | Codex >=0.147.0; four total threads including parent | Headless: MCP tool discovery before work |
The exact host event names are implementation details and can change as a host evolves. The invariant is the outcome, not an assumption that one host's hook taxonomy exists everywhere.
Claude Code adapter
The Claude distribution uses native plugin capabilities and hooks for session bootstrap, rule injection, subagent protocol injection, receipt verification, pre-compaction re-anchoring, and end-of-session snapshots.
Typical event flow:
session start/resume
→ authenticate and refresh policy/skills
→ load canonical lifecycle context
→ dispatch lifecycle agent
→ validate receipt and verification evidence
→ snapshot resumable state
Receipt or verification failure blocks structured execution. Interactive execution surfaces the failure and asks the human how to proceed without pretending that the gate passed.
Codex adapter
Codex uses project instructions, skills/agents, supported hooks, and the Synaptory MCP server. It does not rely on Claude-specific plugin events.
Requirements for the currently certified standard, non-regulated SPQ path:
- Codex
0.147.0or newer; - the Synaptory plugin installed and enabled;
- the Synaptory MCP server visible to the session;
- no more than four total live threads, including the parent thread;
- no cross-host dispatch or handoff.
When an MCP lifecycle call succeeds, re-read canonical state before reporting progress. Do not infer a transition from prose or from an agent finishing its task.
Cursor adapter
Cursor uses project rules, skills, subagents, hooks where supported, and the Synaptory MCP server. IDE and headless execution have different preflight needs.
For headless cursor-agent work:
- verify that the Synaptory MCP tools are discoverable;
- stop if discovery fails;
- confirm the environment's network and privacy policy;
- start or resume the Cycle only after the preflight passes.
Healthcare HC0 execution is allowed only when the organization's Enterprise/BAA, Privacy Mode, and eligible model requirements are all satisfied. A local configuration flag cannot manufacture those guarantees.
Runtime federation is a separate layer
The host adapter governs the lifecycle conversation. An optional runtime adapter executes one dispatch envelope on Claude Code, Codex, or Cursor according to a certified profile.
host adapter
→ SPQ dispatch kernel
→ authorized envelope
→ runtime adapter
→ supervised events + receipt
→ SPQ advance kernel
Installing all three host integrations does not cause them to collaborate. Runtime federation requires explicit runtimes: policy and is intentionally unavailable to legacy Scrum/Kanban flows.
Failure behavior
| Failure | Required behavior |
|---|---|
| Authentication or policy cannot be established | Stop before governed mutation; explain remediation. |
| Canonical state cannot be read | Stop; do not reconstruct state from chat history. |
| MCP lifecycle tools unavailable | Stop host-driven advancement; Cursor headless must fail preflight. |
| Runtime profile unavailable | Keep the Work Unit pending or select another policy-approved profile. |
| Receipt invalid or evidence missing | Do not advance the Work Unit. |
| Runtime dies or exceeds budget | Record the terminal attempt and require governed retry/recovery. |
| Human gate not approved | Remain at the gate. |
Internal implementation files
Host packages contain shell scripts, Python libraries, rules, skills, and MCP wiring. Their paths are intentionally excluded from the public command contract. They may be inspected by maintainers, but users should not run them to create or transition lifecycle state.
For supported operations, use:
- the host entry point for SPQ lifecycle work;
synaptory statusfor general health;synaptory runtimes doctorfor runtime readiness; andsynaptory runtime explain --attempt <id>for attempt authority and evidence.
What's next?
URLs Reference
Diataxis category: Reference — information-oriented.
Every public URL on synaptory.h3t.co, what it does, and which container or static path serves it.
The host is fronted by Caddy; see infra/caddy/Caddyfile for the source of truth.
Per ADR-019 the /console/* and /portal/* URL trees are gone — every page in the Control Plane lives at root URLs.
User-facing URLs
| URL | Purpose | Audience |
|---|---|---|
https://synaptory.h3t.co/ | Role-aware redirect (admin → /overview, else → /home) | Any signed-in user |
https://synaptory.h3t.co/get-started | Public landing — install instructions, links into the user guide | Prospective users |
https://synaptory.h3t.co/home, /overview, /projects/*, /cycles, /attempts, /operations, /agents, /activity, /audit, /sessions, /skills, /cost, /quality, /reliability, /people, /policy, /system, /grafana, /access-review, /settings, /profile | Control Plane pages (Next.js); each role-gated server-side | synaptory-users (varying scope by role) |
https://synaptory.h3t.co/auth/login | Sign-in entry point | Anyone (redirected to Entra) |
https://synaptory.h3t.co/auth/callback | OAuth callback for Web flow | Browser (round-trip from Entra) |
https://synaptory.h3t.co/docs/user-guide.html | This guide, single-file HTML | Anyone signed in (gated by Caddy if needed) |
https://synaptory.h3t.co/docs/getting-started.html | Standalone multi-host onboarding guide | Anyone signed in (gated by Caddy if needed) |
The legacy /console/* and /portal/* URL trees return 404. There are no redirects — bookmarks pointing at the v1.0 surfaces must be updated.
Plugin distribution
| URL | Purpose |
|---|---|
https://github.com/h3tech-ai/marketplace | Public git catalog and supported source for new installations. |
https://synaptory.h3t.co/marketplace.git | Compatibility git catalog for existing Claude Code installations; release-mirrored to GitHub. |
https://synaptory.h3t.co/marketplace | Discoverability landing page. Not the marketplace transport. |
New users run /plugin marketplace add https://github.com/h3tech-ai/marketplace. Existing users on the .git compatibility URL do not need to change it.
CLI distribution
| URL | Purpose |
|---|---|
https://synaptory.h3t.co/cli/install.sh | macOS / Linux install script |
https://synaptory.h3t.co/cli/install.ps1 | Windows install script |
https://synaptory.h3t.co/cli/latest.json | Current CLI version + per-platform binary URLs |
https://synaptory.h3t.co/cli/<version>/<binary> | Versioned binaries (e.g. synaptory_darwin_arm64) |
https://synaptory.h3t.co/cli/<version>/sha256sums.txt | SHA-256 manifest for offline verification |
https://synaptory.h3t.co/downloads | Human-readable download index |
The install scripts resolve latest.json first, then download the binary. Override with SYNAPTORY_CLI_BASE_URL for staging.
API endpoints (/v1/*)
The complete authoritative list is in api/README.md. Highlights:
| Pattern | Audience | Purpose |
|---|---|---|
/v1/auth/* | Anyone | OAuth exchange, local-auth fallback |
/v1/projects/* | Any signed-in user | Project list (caller's by default; ?all=true for global admins). Project detail / members / archive (membership-gated) |
/v1/cycles/* | Authorized project members | Canonical SPQ Cycle operations, plus the two records that must sit outside the executing agent's reach: /v1/cycles/regions/* (the source-region registry, reserved atomically across clones) and /v1/cycles/decisions (the append-only authority-decision store). |
/v1/runtime/* | Authorized project members and registered runners | Governed dispatch attempts, leases, supervision events, cancellation, and reconciliation. |
/v1/projects/{ref}/access-requests* | Any signed-in user | Self-service access requests; project admins approve/deny |
/v1/access-requests/mine | Any signed-in user | Caller's outstanding access requests across projects |
/v1/analytics/* | Any signed-in user (scope-aware) | Analytics with server-side filter by project_members. Anti-leak 404 on ?project=<slug> the caller can't see |
/v1/sessions/* | Any signed-in user (scope-aware) | List, detail, revoke. Self-revoke always allowed |
/v1/admin/* | synaptory-admins only | Cross-tenant operations the role gating doesn't cover: system/*, projects/bulk-archive, config/{v}/export |
/v1/skills/manifest | Any signed-in user | Skill list (no bodies) |
/v1/skills/<name:path> | Any signed-in user | Watermarked body fetch |
/v1/ingest | CLI | Telemetry batch ingest |
/v1/config/* | CLI | Signed config delivery |
/v1/healthz, /v1/readyz | Anyone | Liveness / readiness |
/v1/public-key | Anyone | Ed25519 public key for offline signature verification |
The /v1/me/* namespace was retired by ADR-019. Identity comes from the iron-session cookie's claims; member-scoped reads go through the scope-aware /v1/{projects,sessions,analytics} endpoints.
Operator URLs
| URL | Purpose |
|---|---|
https://synaptory.h3t.co/grafana | Grafana embed (Caddy reverse-proxy, admin-only) |
https://synaptory.h3t.co/system | Probes + versions + last backup |
https://synaptory.h3t.co/audit | Audit log (scope-aware: admins see everything; project admins see their projects) |
Direct Grafana (without the iframe) is also available via SSH tunnel — see infra/README.md.
Local dev URLs
When you run ./synaptory api up, the same surface appears at localhost:
| URL | Equivalent |
|---|---|
http://localhost:8080/ | Role-aware Control Plane root |
http://localhost:8080/<page> | Same page as on prod (e.g. /overview, /projects, /sessions) |
http://localhost:8080/marketplace | Discoverability landing (local). Install from ./web/dist/marketplace or GitHub. |
http://localhost:8080/cli/* | The local web/dist/cli/ |
http://localhost:8080/docs/user-guide.html | The local web/dist/docs/ |
http://localhost:8080/docs/getting-started.html | Standalone onboarding from the local web/dist/docs/ |
http://localhost:8080/v1/* | FastAPI |
http://localhost:8080/dev/mint | Fixture-IDP token mint (local only) |
http://localhost:3099 is the Next.js dev server when running npm run dev directly without Caddy.
Authentication Flows
Diataxis category: Reference — information-oriented.
Three flows mint a SYNAPTORY1 token. Each has a different shape; all produce the same token format, indistinguishable downstream.
For the conceptual model and per-request enforcement, see Identity and access.
Flow 1: Web (Control Plane browser sign-in)
Used by every page in the Control Plane (synaptory.h3t.co/*) — single unified app per ADR-019.
sequenceDiagram participant U as User (browser) participant W as Next.js (web) participant E as Entra participant A as FastAPI (api) U->>W: GET /home (no cookie) W-->>U: 302 → /auth/login U->>W: GET /auth/login W-->>U: 302 → Entra authorize URL (with client_id + redirect_uri) U->>E: GET /authorize E-->>U: Sign-in UI; consent U->>E: POST credentials E-->>U: 302 → /auth/callback?code=... U->>W: GET /auth/callback?code=... W->>E: POST /token (code + client_secret) E-->>W: id_token (JWT) W->>A: POST /v1/auth/exchange (id_token) A->>A: Verify JWKS; extract upn, grp; mint SYNAPTORY1 A-->>W: SYNAPTORY1 token W-->>U: Set-Cookie iron-session; 302 → role-aware home
Key facts:
- The
client_secretis held by thewebcontainer only — never exposed to the browser. redirect_uriregistered as a Web platform on the Entra app (not Mobile/desktop).- The browser carries an iron-session cookie; the SYNAPTORY1 token is held server-side by Next.js.
- The role-aware redirect at the end inspects
grp: admins →/overview, others →/home.
Flow 2: CLI (PKCE)
Used by: synaptory login (default).
sequenceDiagram participant CLI as synaptory CLI participant Browser participant E as Entra participant A as FastAPI (api) CLI->>CLI: Generate code_verifier + code_challenge CLI->>CLI: Bind random loopback port (e.g. 49321) CLI->>Browser: Open https://login.microsoftonline.com/.../authorize?...&redirect_uri=http://127.0.0.1:49321/auth/callback&code_challenge=... Browser->>E: GET /authorize E-->>Browser: Sign-in UI Browser->>E: POST credentials E-->>Browser: 302 → http://127.0.0.1:49321/auth/callback?code=... Browser->>CLI: GET /auth/callback?code=... (loopback HTTP) CLI->>E: POST /token (code + code_verifier; no client_secret) E-->>CLI: id_token CLI->>A: POST /v1/auth/exchange (id_token) A-->>CLI: SYNAPTORY1 token CLI->>CLI: Store token in OS keychain
Key facts:
- No
client_secret. PKCE is a public-client flow;code_verifiersubstitutes for the secret. - The loopback port is bound at runtime; Microsoft's loopback exception means
http://127.0.0.1(no port) is registered as the redirect URI on the Entra app's Mobile/desktop platform, and any port satisfies the match. - The CLI starts a local HTTP server on the bound port for exactly long enough to receive the callback, then shuts it down.
- Same Entra app + same exchange endpoint as Flow 1. Only the front-end shape differs.
For headless servers: synaptory login --device uses Entra's device-code flow instead. The user opens a URL on a separate device, enters a short code, and the CLI polls until success.
Flow 3: Local-auth fallback
Used by: dev fixtures and on-prem deployments where Entra isn't available.
sequenceDiagram participant U as User participant W as Next.js (web) [or CLI] participant A as FastAPI (api) U->>W: POST /auth/login (UPN + password) W->>A: POST /v1/auth/local (UPN + password) A->>A: Compare against SYNAPTORY_CP_LOCAL_*_PASSWORD env vars A->>A: Mint SYNAPTORY1 with grp from the matched slot A-->>W: SYNAPTORY1 token W-->>U: Set-Cookie iron-session
Key facts:
SYNAPTORY_CP_LOCAL_AUTH_ENABLED=trueon the API;SYNAPTORY_LOCAL_AUTH_ENABLED=trueon the web container. Two different env-var prefixes because they live in different containers.- The admin slot grants
[synaptory-users, synaptory-admins]; the user slot grants[synaptory-users]only. - Tokens minted via local-auth are indistinguishable from Entra-minted tokens once issued — the server treats them identically.
- Never enable in deployments expected to use Entra.
The CLI also supports local-auth via synaptory login --local. Same flow, headless.
SYNAPTORY1 token format
SYNAPTORY1.<base64url(payload_json)>.<base64url(ed25519_sig)>
Payload:
| Field | Type | Meaning |
|---|---|---|
sid | string | Server-side session id (used for revoke) |
upn | string | Entra UPN |
grp | string[] | Entra group names; e.g. ["synaptory-users", "synaptory-admins"] |
iat | int | Issued-at (Unix seconds) |
exp | int | Expiry (typically iat + 86400) |
There is no prj claim. Project access is per-request, server-side, against project_members.
The signing key is Ed25519 — file-backed in dev (settings.signing_key_path), Azure Key Vault in prod (kty OKP, curve Ed25519). Public key at GET /v1/public-key.
Refresh and revoke
- Tokens expire (~24h). The CLI silently refreshes via
POST /v1/auth/refreshif possible. - Sessions are revocable from
/sessions(caller's own) or/sessions(any). Revoke flipsrevoked_aton the session row; the next API call returns 401, and the CLI surfaces a re-login prompt. - "Sign out everywhere" hits
POST /v1/sessions/revoke-alland revokes every active session for the caller's UPN.
What's next
- Identity and access — the conceptual model.
- Permissions reference — what each token grants.
- URLs reference — every endpoint and static path.
Permissions Reference
Diataxis category: Reference — information-oriented.
Two axes determine what you can do: whether your Entra identity carries the global synaptory-admins role and your project-level role on each project (member / admin). The legacy synaptory-users group is not a sign-in gate.
For the conceptual model and where checks happen, see Identity and access.
Entra group → platform-level capabilities
| Capability | Signed-in non-admin | synaptory-admins |
|---|---|---|
| Sign in via Entra | ✓ | ✓ |
| Mint a SYNAPTORY1 token | ✓ | ✓ |
Reach Control Plane workspace pages (/home, /projects, /sessions, /audit, /activity, /skills, /profile) | ✓ | ✓ |
Reach admin sidebar entries (/overview, /access-review, /policy, /settings, /system, /grafana/*) | ✗ | ✓ |
Read scope-aware endpoints (/v1/analytics/*, /v1/sessions, /v1/projects) | ✓ (server-side scope clamp) | ✓ |
Read /v1/skills/manifest | ✓ | ✓ |
| Fetch watermarked skill bodies | ✓ | ✓ |
Read /v1/admin/* | ✗ | ✓ |
Provision a new project (./synaptory api projects create) | ✗ | ✓ (operator path) |
| Revoke any user's session | ✗ | ✓ |
| View any user's receipts | ✗ | ✓ |
| Read project membership for projects you're not on | ✗ | ✓ |
Any valid tenant identity can sign in. synaptory-admins adds global administration; project data still follows server-side project scope.
Project role → project-level capabilities
These are checked per project, on top of group permissions, by check_project_membership.
| Capability | Non-member | member | admin (project) |
|---|---|---|---|
See the project on /projects | ✗ | ✓ | ✓ |
Read /v1/projects/<slug> | ✗ (404) | ✓ | ✓ |
Read /projects/<slug> overview | ✗ (404) | ✓ | ✓ |
Run /synaptory against the project's source tree | ✗ (CLI sees 404) | ✓ | ✓ |
See receipts for this project on /audit | (not shown) | ✓ (own receipts only) | ✓ (own receipts only) |
| Invite a member | ✗ | ✗ | ✓ |
| Revoke a member | ✗ | ✗ | ✓ |
| Promote a member to admin | ✗ | ✗ | ✓ |
| Modify project settings | ✗ | ✗ | ✓ |
Important: synaptory-admins does not automatically get admin on every project. A global admin who wants to invite a member to a project they aren't on goes through the project's Members tab (allowed by the /v1/admin/* capability above) — not the project-admin self-serve path.
What synaptory-admins can do that project admin can't
Some operations are platform-wide and require the Entra group, not project role:
- Create a new project (
./synaptory api projects create <slug>— currently CLI-only). - Archive / unarchive a project.
- Read
/auditacross all projects. - Read
/costand other analytics across all projects. - Read
/v1/system/health. - Modify the signed config that the CLI fetches.
- Revoke another user's session (members can revoke only their own; admins can revoke anyone's via
/sessions).
What no one can do
Some properties are out of band — not granted by any role.
- Read encrypted skill bodies at rest. They're envelope-encrypted with a KEK in Azure Key Vault. Even DB access doesn't help — you'd also need Key Vault access plus the deterministic UPN-watermark would still trace any leak.
- Modify the immutable parts of receipts. Receipts are append-only; the
receiptstable has no UPDATE path in the API. - Forge an Entra group. The
grpclaim is set at sign-in from the Entra ID token. Tampering with the SYNAPTORY1 token breaks the Ed25519 signature.
Anti-enumeration patterns
A few permission checks return 404 (not 403) on purpose, to avoid leaking the existence of resources you can't see.
| Scenario | Status |
|---|---|
| You're not a project member, project exists | 404 |
| You're a project member, project archived | 403 (you can see it but can't modify) |
| Project doesn't exist at all | 404 |
This is why "user reports they got 404 on a project they should have access to" is the #1 access-control debug signal — there are three possible causes (not a member, project archived, project missing), and they look identical from the client.
What's next
- Auth flows — how the
grpclaim is set. - Identity and access — the per-request enforcement model.
- Inviting members — the workflow.
Glossary
Diataxis category: Reference — information-oriented.
This glossary uses the current SPQ-first vocabulary. Scrum and Kanban terms remain only where compatibility behavior still exists.
Lifecycle and hierarchy
| Term | Definition |
|---|---|
| SPQ | The proper name of Synaptory's primary governed delivery method. Its lifecycle is four stages -- Discovery, Cycle, Acceptance, Complete -- and Commit / Sync / Checkpoint are recorded events, not stages. |
| Project | The durable product or service boundary governed by one Synaptory configuration. |
| Engagement | One project's whole delivery: the approved baseline, the shared trunk, and every Acceptance. Ended by the final Acceptance and nothing else. |
| Cycle | The SPQ delivery unit and the only unit of parallelism: a scope-defined set of Work Units sealed at Commit, executed and proved, integrated to the shared trunk at its barrier, and demonstrated at Checkpoint. One Engineering Lead, one Crew, one repository. |
| Work Unit | The smallest governed unit of delivery. It carries its own dispatch, attempts, evidence, acceptance state, and its declared path scope. |
| Discovery | Request, analysis, and the first planning work that produces a proposed baseline. It ends at human baseline approval, which includes a measured calibration sample -- a git sha and a boolean do not satisfy it. |
| Commit | The event that opens a Cycle by sealing a non-empty admitted set. The seal is what closes the set, not the event: nothing joins a Cycle afterwards. |
| Sync | The event recording that one Cycle waited on a result from another and how it cleared. It has zero or more occurrences and blocks nothing. What blocks a Work Unit is an unsatisfied dependency. This entry previously read "the cross-workstream integration barrier", which is exactly what SPD-194 retires. |
| Barrier | The all-or-nothing mechanical condition a Cycle must meet to close, evaluated over the admitted set minus recorded cuts. Its criteria are published at Commit from one constant. It lives at Checkpoint, not at Sync. |
| Checkpoint | The event recording the demonstration, the barrier verdict, the integrated trunk revision and the cut list. |
| Cut | The one valve. Withdrawing unfinished work from a Cycle with an explicit reason, a backlog return and a key a later Commit can name. It never moves the approved baseline. |
| Source region | The repository-relative paths a Cycle may address. Overlapping regions are refused at declaration, which is what lets concurrent Cycles stay independent. |
| Path scope | The paths one Work Unit may change. Required at admission. Intersecting scopes are refused unless each declares a distinct execution_order; disjoint work proceeds with no enablement. |
| Crew | The people and agents seated on one Cycle. It grants nothing and is re-seatable between Cycles without changing a single barrier admission. |
| Engineering Lead | The accountable human named per Cycle. A role decides who may be named and confers no reach. |
| Trunk | The one shared branch a Cycle integrates into at its Checkpoint. A Cycle that closes having integrated nothing anyone else can see has not closed. |
| Acceptance | A go-live: its own evidence package and its own human decision. Repeatable -- delivery continues in another Cycle meanwhile. Only the final Acceptance closes the engagement and records the handover. |
| Release | A governed promotion. A human gate, not an automatic consequence of Acceptance. |
| Scrum / Kanban | Legacy compatibility lifecycles. Existing projects may finish or migrate, but new guidance and runtime federation target SPQ. |
Retired terms
Recorded rather than deleted, because they appear in receipts, gate events and sealed declarations from before SPD-194 and a reader of an archived record needs to know what they meant and what replaced them.
| Retired term | Meant | Read instead |
|---|---|---|
| Workstream | A durable lane within a Cycle, with its own branch and readiness record | Nothing. The Cycle is the unit; a Work Unit's path scope carries what the lane's file ownership carried, and a Crew carries the staffing without the durability |
| Coordination Cycle | A parent grouping child Cycles, pinning each child's SHA and composing release readiness | Nothing. It existed only because integration was deferred; with the barrier integrating to trunk at Checkpoint there is nothing downstream to gather |
| Cycle of Cycles | Folk term for the same parent layer. Never entered the method | Nothing |
| Integration seat / integration workstream | A barrier seat outside the delivery quorum | Nothing. There is one board per Cycle and one barrier over it |
| Sync as barrier | The all-or-nothing integration gate | The barrier at Checkpoint. Sync is a record of a dependency having cleared |
Hosts and runtimes
| Term | Definition |
|---|---|
| Host | The interactive coding environment in which the user invokes Synaptory: Claude Code, Codex, or Cursor. |
| Host adapter | The integration that maps a host's instructions, skills, hooks, agents, and MCP support onto Synaptory governance. |
| Runtime | An agent execution engine used for one governed attempt. A runtime may be the same product as the current host or a different approved engine. |
| Runtime federation | Optional SPQ-only routing of Work Units across certified runtime profiles. It must be explicitly configured. |
| Runtime family | The underlying execution product, such as claude-code, codex, or cursor. |
| Placement | Where a runtime executes, currently local or managed-laptop in the pilot profiles. |
| Adapter profile | A certified combination of runtime family, placement, pinned version, capability profiles, and capability ceiling. |
| Capability profile | A skill-composition label—analyst, planner, producer, or prover. It grants no authority. |
| Stage profile | One of the seven obligation locations: admitting, analysing, planning, producing, verifying, releasing, or operating. |
| Capability ceiling | The maximum tools, network scope, filesystem access, and other authority a runtime attempt may receive. |
| Dispatch envelope | The immutable, validated instruction for one attempt: identity, lifecycle binding, role, profile, budget, authority ceiling, required evidence, expiry, and receipt path. |
| Attempt | One execution of a Work Unit through a runtime adapter. Retries create distinct attempts without rewriting history. |
| Runner | A registered machine able to serve one or more runtime profiles under a lease. |
| Lease / fencing | Control-plane mechanisms that grant temporary ownership of work and reject stale workers after ownership changes. |
Governance and evidence
| Term | Definition |
|---|---|
| Canonical state | The authoritative lifecycle record. Conversation text and runtime-native session state are not canonical. |
| Receipt | Structured evidence returned by an agent or runtime attempt, including artifacts, verification commands, metrics, identity, and completion metadata. |
| Evidence | Verifiable proof required by a Work Unit or gate: tests, commands, artifacts, reviews, approvals, or policy-specific records. |
| Definition of Done (DoD) | Project-level quality requirements that are incorporated into SPQ evidence policy. Legacy modes also use story/sprint DoD terminology. |
| Dispatch kernel | The governance boundary that validates state, policy, authority, runtime eligibility, and idempotency before issuing an envelope. |
| Advance kernel | The governance boundary that validates the attempt and its evidence before advancing a Work Unit. A runtime cannot advance itself. |
| Human gate | A decision that automation may prepare but cannot approve: baseline approval, the admitted set at Commit, a cut, the Checkpoint close, and Acceptance / completion. Sync is not one -- it records a dependency having cleared and authorizes nothing. |
| Idempotency | Repeating the same authorized request does not create duplicate canonical transitions. |
| Append-only history | Prior lifecycle events and attempts remain auditable rather than being overwritten. |
| Fail closed | If authority, policy, state, or evidence cannot be established, Synaptory stops instead of silently weakening the rule. |
Product and identity
| Term | Definition |
|---|---|
| Plugin | A host-specific Synaptory distribution. Claude Code, Codex, and Cursor packages share lifecycle semantics but use host-native integration mechanisms. |
| CLI | The standalone synaptory binary used for authentication, policy/skill sync, diagnostics, telemetry, and the Runtime Bridge. |
| Control Plane | The Synaptory web application and API for projects, Cycles, Acceptances, attempts, supervision, policy and administration -- plus the two records that must sit outside the executing agent's reach: the source-region registry and the authority-decision store. A process-local lock cannot be atomic across clones. |
| MCP | Model Context Protocol. Codex and Cursor use Synaptory MCP tools for governed lifecycle operations. |
| UPN | User Principal Name from the configured Entra identity. |
| Tracker adapter | An optional integration for local or remote issue/project tracking. Trackers mirror delivery work; they do not replace canonical SPQ state. |
| Engagement mode | structured or interactive; controls how much autonomy Synaptory uses between required human gates. |
| Healthcare mode (HC0) | A regulated operating profile that requires the relevant enterprise agreement, BAA coverage, privacy settings, eligible models, and policy. It is not enabled by a local flag alone. |
Compatibility role abbreviations
| Abbreviation | Role |
|---|---|
| PO | Project Owner |
| SA | Solution Architect |
| SE | Software Engineer |
| QE | Quality Engineer |
| CR | Code Reviewer |
| CE | Compliance Engineer |
| PE | Platform Engineer |
| TW | Technical Writer |
| RA | Research Advisor |
See Agents for how roles participate in SPQ.
Troubleshooting
Start with the smallest read-only check that can identify the failing layer. Do not edit canonical lifecycle files or invoke internal hook/state-machine modules to force progress.
Fast triage
Run from the project root:
synaptory whoami
synaptory status
synaptory runtimes doctor
Then ask the active host:
Run Synaptory doctor and show the current canonical Cycle.
Interpret the layers independently:
| Layer | Healthy signal |
|---|---|
| CLI and identity | whoami shows the expected UPN and an unexpired session. |
| Project | projects current resolves the expected project. |
| Host integration | The Synaptory entry point loads and lifecycle tools are visible. |
| Canonical lifecycle | The host can read the current Cycle, stage, gates, and Work Units. |
| Runtime federation | Every required profile is ready; optional profiles may be not-ready. |
Installation and host issues
The Synaptory entry point is missing
- Claude Code: confirm the marketplace and plugin are installed, then restart the session.
- Codex: confirm the plugin is installed/enabled and Codex is
0.147.0or newer. - Cursor: confirm project rules, skills, agents, hooks, and MCP configuration were installed into the project.
Re-run the relevant steps in Getting Started.
Claude Code starts but hooks cannot find the CLI
Run:
command -v synaptory
synaptory version
Restart Claude Code after installing or updating the CLI so its environment sees the new PATH.
Codex cannot run the SPQ lifecycle
Check all of the following:
- Codex version is at least
0.147.0; - the Synaptory plugin is enabled;
- the Synaptory MCP server is visible;
- no more than four total live threads exist, including the parent;
- the request is standard non-regulated SPQ work.
Codex is not currently a certified host for regulated SPQ or cross-host handoff.
Cursor headless cannot start governed work
Treat missing MCP tools as a failed preflight. Do not continue from remembered chat state. Fix MCP configuration/tool discovery and start a new governed attempt.
For HC0 work, also verify the organization's Enterprise/BAA, Privacy Mode, network, and eligible-model requirements. A successful local command does not prove compliance.
Authentication and project access
Browser sign-in did not open
Use device flow:
synaptory login --device
Session expired or sign-in is requested repeatedly
synaptory login
synaptory whoami
If the cached identity is not the intended account, run synaptory logout and sign in again.
Project not found or access denied
synaptory projects list
synaptory projects current
Confirm the project_id in .synaptory.yaml and ask a project administrator to verify membership. Authentication proves identity; project membership is authorized per request.
Skills or policy are stale
synaptory skills sync
synaptory config fetch --if-stale
synaptory config env
Restart the host session after a material plugin or policy update.
SPQ lifecycle issues
No active Cycle exists
First confirm the project is configured for SPQ:
schema_version: "1.0"
build_mode: spq
Then ask the host to start a Cycle with a bounded outcome. Initialization and Cycle creation are separate operations.
The Cycle appears stuck
Ask for the canonical state and the exact unmet prerequisite:
Show the current Cycle, stage, open gate, pending Work Units, and missing evidence.
Common legitimate pauses are:
- Shape is waiting for Sync approval;
- a dependency prevents a Work Unit dispatch;
- Checkpoint evidence is incomplete or invalid;
- Acceptance is waiting for a human decision;
- Release has not been explicitly approved.
Do not edit .synaptory/ state files or run internal transition scripts. Correct the evidence or make the required human decision through the host adapter.
A Work Unit failed repeatedly
Inspect the attempt rather than overwriting it:
synaptory runtime status --attempt <attempt-id>
synaptory runtime explain --attempt <attempt-id>
Identify whether the cause is a capability refusal, missing dependency, budget ceiling, runtime death, invalid receipt, verification failure, or human decision. A governed retry creates a new attempt and preserves the prior evidence.
Receipt or Checkpoint validation fails
The failing report should name missing fields, artifacts, or verification evidence. Re-run the bounded producer/prover work or correct the artifact, then run Checkpoint again. Switching engagement mode may change how the problem is presented; it does not turn invalid evidence into valid evidence.
Canonical state and host conversation disagree
Canonical state wins. Start a fresh turn/session, re-read the Cycle through the host adapter, and resume from the recorded stage. Never reconstruct lifecycle state from a summary or manually “catch up” the files.
Runtime federation issues
A profile is listed but not-ready
runtimes list shows recognized profiles; it does not prove the underlying runtime is installed. Run:
synaptory runtimes doctor --profile <profile-id>
Follow the reported version, executable, placement, or policy remediation. Keep optional profiles optional; do not lower the Work Unit's capability requirement merely to make a runtime eligible.
Runtime policy has no effect
Confirm all three conditions:
build_mode: spqis active;.synaptory.yamlcontains a validruntimes:block; and- the relevant capability profile maps to a certified adapter profile.
Runtime routing is deliberately inert in Scrum and Kanban compatibility modes.
Cancellation says “recorded locally only”
The local attempt record was updated, but the command could not prove delivery to the control plane/worker. Do not claim that the remote runtime stopped. Check supervision state, restore connectivity, and issue a governed follow-up from the machine or control-plane surface that owns the lease.
Runtime output exists but the Work Unit did not advance
Runtime success is not lifecycle acceptance. Check the receipt, required evidence, manifest binding, and Checkpoint result. Only the advance kernel can complete the Work Unit.
Configuration issues
Configuration is not detected
Confirm .synaptory.yaml is at the project root from which the host was opened:
ls -l .synaptory.yaml
synaptory projects current
Unexpected Scrum or Kanban behavior
The compatibility default may still apply when build_mode is omitted. Set it explicitly:
build_mode: spq
For an existing legacy project, follow Migrate to SPQ instead of rewriting its historical state.
Tracker updates fail
Confirm the provider credentials and project/team identifiers documented in Configuration. A tracker is a projection of delivery work; a tracker outage must not be repaired by fabricating a canonical SPQ transition.
For GitHub, distinguish network failure from credential rejection before re-authenticating: remove accidental GH_TOKEN/GITHUB_TOKEN overrides, verify connectivity, then treat only a real GitHub 401 Bad credentials response as an authentication failure.
Control Plane and telemetry
Control Plane data looks stale
synaptory outbox list
synaptory outbox flush
Then refresh the relevant Cycle or attempt. A queued outbox affects observability; it does not authorize a local lifecycle transition.
A control did not complete
Read the UI result carefully. If the page says the request was not sent or not confirmed, assume no state change occurred. Re-read canonical state before retrying so idempotency keys and lease ownership remain valid.
Legacy project issues
Scrum and Kanban remain compatibility paths while retirement is planned. Existing project troubleshooting is preserved in the legacy guide pages, but new Work Units and runtime federation should move to SPQ.
Reporting a product issue
Capture:
- host and version;
synaptory versionandsynaptory statusoutput with secrets removed;- project and Cycle/Work Unit/attempt identifiers;
- the exact failed operation;
- the displayed error and whether canonical state changed;
synaptory runtimes doctoroutput when runtime federation is involved.
Then ask Synaptory to submit a support report or use synaptory report submit. Do not attach tokens, runtime credentials, or sensitive source content.
If the report fails to send
The control plane relays the report to GitHub, so a submit can fail for reasons on our side: an expired credential, a GitHub incident, an unreachable control plane, or a session that needs synaptory login. Your text is not lost. A failed submit writes it to ~/.synaptory/.failed-reports/ (or ~/.synaptory-local/.failed-reports/ for the local build) and the error names the two files it wrote:
<timestamp>-<project>-<title>.mdis the report body on its own, ready to
open or attach to an email;
<timestamp>-<project>-<title>.jsonis the whole request, which you can
replay once the relay is back:
synaptory report submit --json ~/.synaptory/.failed-reports/<file>.json
Nothing deletes these files, and nothing retries them in the background. They stay until you file the report or remove them yourself. If the error says the report could not be preserved, copy it out of your terminal before closing the session.
If retrying keeps failing, send the .md file to support@h3t.co. Do not try to file the issue on GitHub yourself: the issues repository is private, which is the reason the control plane relays reports in the first place.
H3T staff only. You do have filing rights, but not through a bare
gh. The local identity guard refuses a mutation on anh3tech-airepository with exit status 13. Filing a defect is the "Prove" authority class, so hand the saved body to the role-bound wrapper:h3t-gh-tester issue create --repo h3tech-ai/synaptory-v1 \ --title "<title from the .json>" \ --body-file ~/.synaptory/.failed-reports/<file>.mdNote this loses the server-side UPN / project / session stamp the relay adds, so say in the body who hit it and on which project.