Skip to main content
Vellum is now Figentra Flow (renamed 2026-11-01).
Amended 2026-11-01 by 0510: decision 10’s .specify/ folder becomes .flow/, and the spec-workflow CLI is Figentra Flow (figentra-flow); the name “Vellum” is retired.
Accepted 2026-10-31: the owner decided the four CLIs and the script map on 2026-10-31 (“all 33+ commands … and test”; “figentra repo and start all”). Amends 0282 (decisions 4, 11, 13 to 16; see its amendment of 2026-10-31). Adds no registry scope: all three public CLIs are @stackra/* (0453 decision 10). Number: 0500, chosen clear of 0494 (used on two open branches) and of the gap 0495 to 0499.
Amended 2026-10-31 (owner decision D2 of the Vellum final plan): decision 12 now reads that there is no stackra spec command. stackra check’s spec phase calls vellum gate ci and vellum trace ci when Vellum is installed. The earlier text kept stackra spec as a thin alias until the owner decided.

Context

Core holds 33 hand-written scripts in tools/scripts/*.mjs, and every product repository copies them, so the copies drift. CI and the product repositories run them through per-member loops. 0282 put the open operations into @stackra/cli but left Figentra-internal operations in tools/scripts and made Figentra Flow the SDLC only if a spike (STA-298) passed. The old figentra/flow is a large multi-package product that the spike never reached. 0453 made the Stackra registry the only channel, and 0461 set what is free and what is Pro. On 2026-10-31 the owner decided that every command lives in exactly one of four CLIs, installed like any dependency, with package.json scripts as aliases and Turborepo tasks calling the CLIs.

Decision

The four CLIs

  1. Four CLIs, one home each.
  2. Stackra registry only. All four publish to https://npm.stackra.figentra.com/ from their repository’s release workflow through GitHub OIDC (0453 decision 6), never to npmjs and never to npm.figentra.com. The figentra/flow release workflow becomes a trusted publisher of the @stackra scope for @stackra/vellum only. The @figentra internal row of 0453 decision 10 gains the figentra/figentra release workflow as a trusted publisher; only Figentra’s internal tokens read it, so @figentra/cli never reaches a customer.
  3. Scope of each CLI.
    • stackra: the open developer operations of a Stackra project (scaffold, gen, validate, structure, checks and ratchets). Its existing commands (gen, new, check, verify, validate, structure, spec, docs, code:fix) stay.
    • runway: deploy, promote and status for a Runway project.
    • figentra-flow: the spec workflow (decision 9): init, sync, gate, trace, parse, linear, later migrate.
    • figentra: Figentra-internal operations: Linear, the bot identities, the merge gate, the secrets inbox, delegation, the spend meter, the agent projection of this repository, brand pull and the guard port. Nothing in it ships to a customer, and @stackra/cli never imports it.

The script map

  1. All 33 scripts move. Each script in tools/scripts maps to exactly one command: That is 16 for stackra, 5 for figentra-flow, 1 for runway and 11 for figentra. The data files beside the scripts (any-ratchet.baseline.yaml, duplication-baseline.yaml) stay in each repository and the command reads them from there. New stackra commands also include those the plan names for Turborepo (stackra check tasks per member).
  2. What stays in each repository. Its specs (.agents/specs/), its installed .specify/ folder, its constitution, its baselines, and its repository facts the validator reads. A repository keeps no copy of a moved script.

How a command moves

  1. package.json scripts stay as one-line aliases. Every moved command keeps its root script name, and the script becomes one call of the CLI, with the same wrapper it had: "runway": "runway", "linear": "infisical run --env=dev --path=/agents --silent -- figentra linear". Turborepo tasks call the CLIs directly. No alias holds logic, a pipe or a loop.
  2. A moved command keeps its behaviour, tests and output. The script body becomes the command; flags, exit codes, stdout and stderr do not change in the move, and its __tests__ move with it into the CLI package. Behaviour changes come after, in their own commits. Before a move lands, the command runs once on the ci-box against the old script’s output, and the full core gate passes.
  3. Secret guards change in the same commit. bot-token, secrets-import, linear and the infisical run wrappers are matched by .agents/hooks/_rules.mjs and by the OpenCode guard (.opencode/plugins/guard/decide.ts). A commit that moves any of them, or changes its alias, updates both guards and their tests in that same commit, and pnpm test:hooks passes. No agent reads a secret value at any point of the move.

Figentra Flow

  1. Figentra Flow is the spec workflow, fresh. The current figentra/flow main is tagged legacy-2026-10-30, then main is replaced by one package with one binary. The Stackra preset (.specify/presets/stackra), the spec scripts of decision 4, the speckit-* skills and notes/sdd-sdlc-plan.md move into it. Core then runs figentra-flow sync instead of speckit-sync.mjs.
  2. .specify/ stays for now. spec-kit’s specify CLI and the ten speckit skills expect it, so Figentra Flow reads and writes .specify/ while it wraps spec-kit. When Figentra Flow replaces spec-kit, one figentra-flow migrate command moves a repository from .specify/ to .figentra-flow/; until then nothing writes .figentra-flow/.
  3. No Claude Code plugin for now. figentra-flow sync writes skills and commands into .agents/, and the repository’s agent projection (figentra agents sync here, stackra agents sync in a customer project) renders them into .claude/ and .opencode/, so both agents work. A plugin can come later, for outside users, through its own ADR.
  4. No stackra spec command (amended 2026-10-31). stackra check’s spec phase calls figentra-flow gate ci and figentra-flow trace ci when Figentra Flow is installed; every other spec command is figentra-flow’s alone.

Rollout

  1. Order. The four CLI builds run in parallel, one helper per CLI, each on its own worktree and branch, each gated on a ci-box, and they start after Stackra 0.1.1 publishes:
    1. this ADR and the amendment of 0282;
    2. stackra: the new commands, with Turborepo tasks calling them (on the chore/turbo-tasks gen work);
    3. figentra-flow: the legacy tag, the fresh skeleton, then the preset, scripts and skills; core switches to figentra-flow sync;
    4. runway: a binary in the existing package; pnpm runway becomes an alias;
    5. figentra: the package in figentra/figentra, with the guards updated in the same change (decision 8).
    Then the repositories switch to the published CLIs, in this order: stackra-template, os, commerce, stackra-pro, then the nine .next repositories (academorix, juristra, organza, velora, mezzora, jute, figentra, pay, tamo), each together with the turbo gen recipe. A repository deletes its copied scripts in the commit that adds the aliases.

Consequences

  • One fix to a command reaches every repository through a version bump; the copies stop drifting.
  • Four packages carry release checks and changesets, and two more repositories (figentra/flow, figentra/figentra) need release workflows trusted by the registry.
  • The secret guards depend on command names; every rename is a guard change, which decision 8 makes explicit.
  • Customer projects lose nothing: everything they ran is in stackra, runway or figentra-flow; only Figentra-internal operations move to the private CLI.
  • Figentra Flow wraps spec-kit until figentra-flow migrate, so 0067 and the specify-cli pin stay in force for now.
  • Chore: the owner tags legacy-2026-10-30 in figentra/flow before main is replaced.

Enforcement

  • pnpm test:hooks (.agents/hooks/__tests__/*.test.mjs, .opencode/plugins/guard/__tests__/*.test.ts) runs the guard tests that decision 8 updates with each move.
  • The registry refuses a publish from a workflow that is not the scope’s trusted publisher, and refuses unknown scopes (0453 decisions 6 and 10).
  • planned — a validator check in stackra validate that fails when a root package.json script for a moved command is more than one CLI call (decision 6), or when tools/scripts/ holds a script decision 4 has moved.
  • planned — a packed-tarball test of @stackra/cli, @stackra/runway and @stackra/vellum that fails if a figentra command (decision 3) is present.
  • planned — a check that every package of decision 1 has publishConfig.registry set to https://npm.stackra.figentra.com/.
  • planned — the parity run of decision 7 as a ci-box job per moved command; until it exists, the run is a manual gate step recorded in the PR.
  • Nothing checks the legacy-2026-10-30 tag or the rollout order; they are owner and lane steps tracked in Linear.

Supersedes and sources

Supersedes: none. Amends: 0282 decisions 4, 11, 13, 14, 15 and 16. Related: 0067, 0083, 0121, 0453, 0461. Sources: owner decisions in chat, 2026-10-31; plan notes/plans/clis-and-vellum.md (decisions and the full script map).