# farketari

Implements a full feature — Gherkin scenarios to committed, pipeline-green
vertical slices — for projects built on the nextjs-fastify stack's
architecture (Fastify api-server with DDD/CQRS bounded contexts, Next.js
web app, React Native mobile app, feature-flags admin console, OpenAPI
contract, acceptance layer with DSL + protocol drivers).

The orchestration is deterministic code; every leaf step (write a test,
design an aggregate, extend a repository) is delegated to a model chosen
per work kind (hard / intermediate / easy tiers). The full specification
of the algorithm — two variants keyed on `tddMode`, the standing rules,
every inner loop — lives in [algorithm.md](./algorithm.md), which ships
with the package.

## Status

Working today: `bootstrap` and `validate-template`. `implement` wires the
whole run and validates its inputs, then throws `NotImplementedError`
naming the first role method to build — the walking skeleton's honest
answer.

The orchestration, the configuration surfaces, and the algorithm
specification are complete, and the deterministic core is driven
end to end in the test suite by a fake step executor. Implemented for
real:

- `claudeStep` — the one leaf executor that launches a model, as a Claude
  Code session via the Agent SDK. Every AI step is a WorkOrder run
  through it.
- `shellCommandRunner` — catalog commands executed from the project root.
- `bootstrapFromStack` — the `bootstrap` command, end to end.
- `escalationTo` — stop-and-flag to the console, and to
  `escalation.webhookUrl` when a project configures one.
- `bootstrapProject` + `fileBootstrapper` — the older, model-driven
  bootstrap specified in [bootstrap.md](./bootstrap.md), which strips a
  full example down to its architecture (what survives is
  `bootstrap-rules.ts`). Shipping a skeleton beside each example made it
  unnecessary, so **the CLI no longer runs it**; it stays a library
  export for stacks that ship an example alone.

The implement command's roles are ALSO real (`buildLiveDeps` — what the
CLI runs on): `claudeOrienter`, `claudeAcceptanceAuthor`,
`claudeContractAuthor`, the three client agents, `claudeBackendAgent`,
`claudeReviewer` and `claudeRemoteJudge` are thin compositions over
`claudeStep` (phrase the task, run the session, strictly parse the final
JSON — `model-output.ts`). Steps are one-shot by default, with two token
levers on top: the SESSION LEDGER (`session-ledger.ts`) records what
every session changed — derived from the tree around the session, never
self-reported — and briefs later sessions with it inside their task
text, so they read the named files instead of re-surveying the
repository; and the acceptance author chains its four authoring steps
into ONE resumed conversation per slice (`SessionHandle` in
`claude-step.ts`), reset at each slice's opener — judgments stay
one-shot and unbriefed on purpose. `fileRunJournal` persists the resumable
checkpoint under `journalDir` (default `.farketari/`); `gitTrunk`
integrates continuously — a checkpoint commit (gated, pushed, pipeline
not awaited) at every mid-slice point the tree is green by construction
(the @wip-marked acceptance spec at slice open, the additive contract,
the join barrier, the wired real API; the stack's CI acceptance jobs
exclude @wip-titled tests via their ACCEPTANCE_WIP_FILTER variable, and
the markers are stripped at the final commit; checkpoints commit with
--no-verify, and the stack's version-bump guard defers "slice: <name> —
<label>" commits to the slice's final commit, where
scripts/bump-changed-versions.sh patch-bumps every deployable the slice
changed). Inside the fan-out, every checklist item a lane proves green
becomes a LANE-SCOPED work-preservation commit (`commitLaneProgress`:
stage only that lane's context-scope paths — a sibling lane's mid-TDD
red state never rides along — commit --no-verify, local only; the next
barrier checkpoint pushes the accumulated lane commits, and the lanes'
commits are serialized in-process because they share one git index) —
then commits each
finished slice and awaits its GitLab pipeline (reads
gitlabHostname/ProjectId from the project's global configuration; needs
`FARKETARI_READ_JOBS_TOKEN` with read_api — decrypted from the project's
sops secrets tree, or an env override of the same name; that is the ONLY
name read, and the run stops at its start-of-run preflight when the
token is missing or cannot read the project, rather than pretending the
pipeline was green); `claudeGateRepair` routes red gate
commands (typecheck, localization, migrations) to budgeted repair
sessions that fix the state the gate checks — never the gate itself —
before any stop-and-flag; `quiescentTreeCoordination` approximates the
stable-tree wait by sampling the tree's change signature. `buildDeps`
still returns `stubRole` proxies — the library default for callers who
compose their own roles; the scripted end-to-end in
`implement-e2e.test.ts` proves the whole pipeline over fakes.

## CLI

```sh
farketari implement <feature-file> [--example <path>] [--tdd] [--instructions <text>]
farketari validate-feature <feature-file> [--example <path>]
farketari bootstrap <target-dir> --name <project-name> --stack <name>
                    [--stack-version <version>] [--ref <ref>] [--repo <url>]
farketari validate-template <template-path>
```

### `validate-feature`

Gate 0, standalone: judges a feature file's scenarios against the same
writing rules `implement` enforces before planning — one cheap model
review (~$0.50, a minute or two), findings printed with paste-ready
fixes, exit code 1 when the file would stop an implement run. Polish the
spec in review rounds first; spend the implementation run when it
passes. Read-only by the same contract as the in-run gate: the feature
file is never modified.

### `implement`

- `<feature-file>` — the `.feature` file to implement, relative to the repo root.
- `--example <path>` — path to the example project: a repository with the
  same architecture where every pattern the algorithm must produce
  already exists, done right. Prompts cite files under it. Required
  unless `farketari.ts` sets `exampleProjectSource`, which this flag
  overrides.
- `--tdd` — strict test-first (Algorithm 1). Without it, tests are written
  with the code (Algorithm 2).
- `--instructions <text>` — run-specific instructions, appended to the
  project's standing `runInstructions`.

### `bootstrap`

Creates a new project from a stack's SKELETON: the full architecture —
bounded contexts with their CQRS split, the clients, the acceptance
harness, toolchain and CI — with none of the example app's substance (no
use cases, domains, components, or specs).

A stack is two projects kept in step by hand: the EXAMPLE, and the
SKELETON that is the same architecture with the example's features
already removed. So bootstrapping is not a transformation to be derived,
it is a fetch, a copy and a rename — **no model runs and nothing is
billed**. The skeleton's own `projectName` is the placeholder every
substitution keys on.

- `--name <project-name>` — kebab-case name of the new project; becomes
  its identity everywhere the skeleton named itself.
- `--stack <name>` — **required**, e.g. `nextjs-fastify`. Which stack decides
  the project's whole architecture, so it is named deliberately rather than
  defaulted into.
- `--stack-version <version>` — which generation of that stack (default `v1`).
- `--ref <ref>` — branch, tag or commit of the stacks repository; pin a
  tag for a reproducible start (default `main`).
- `--repo <url>` — the repository holding the stacks; point it at a fork.

The target directory must not exist or must be empty — bootstrapping
never writes into existing work. The new project's `farketari.ts` is
repointed at the matching example, so `implement` needs no `--example`
afterwards.

### `validate-template`

Validates a template checkout's descriptor; see [Templates](#templates).

## Library

```ts
import { implementFeature, buildDeps, shellCommandRunner } from "farketari";

await implementFeature(
  { ...buildDeps(), commandRunner: shellCommandRunner(process.cwd()) },
  "behavior/features/withdraw-money.feature",
  { tddMode: true, examplePath: "/path/to/example-project" },
);
```

`buildDeps` returns real configuration and STUBBED roles, so this run
stops at the first role call until you supply your own — see
[Status](#status). Override any of them the same way `commandRunner` is
overridden above; `stubRole` covers the ones you have not built yet.

## Project configuration

A project carries a `farketari.ts` at its repository root (found by
walking up from wherever the command runs), default-exporting a
`FarketariConfig`. Everything is optional; precedence is CLI flag >
`farketari.ts` > template descriptor > built-ins:

```ts
import type { FarketariConfig } from "farketari";

const config: FarketariConfig = {
  // The example project this one follows: a GitHub directory URL
  // (fetched into a local cache and pinned at first fetch), or a
  // filesystem path relative to this file. `bootstrap` writes the URL
  // form. Makes --example optional on every command.
  exampleProjectSource:
    "https://github.com/redjolr/farketari/tree/main/stacks/nextjs-fastify/v1/example",
  projectName: "acme-banking",
  tddMode: true,
  // Per participant ("mobile-app", "backend") or per test level
  // ("mobile-app-acceptance", "mobile-app-e2e", "use-case-unit",
  // "event-handler-unit"); a level's own key wins over its participant's,
  // and only an explicit "<platform>-acceptance" key changes the outer
  // discipline (red-check vs. driver dry-run at slice end).
  tddModeOverrides: { "mobile-app": false, "mobile-app-acceptance": false },
  clients: ["web-frontend", "feature-flags-admin"], // narrow the template's platforms
  runInstructions: ["Domain language: ..."], // injected into every run
  budgets: { infrastructureRetries: 5 },
  models: { roster: { easy: { model: "deepseek-v4-pro", baseUrl: "https://api.deepseek.com/anthropic" } } },
  commands: { remote: { android: { syncTree: "task remote:sync" } } }, // fill in the runner vocabulary
  prompts: { "client-implementation": "farketari-prompts/client-implementation.md" },
  journalDir: ".farketari", // not read yet — see Status
  trunk: { branch: "main" }, // not read yet — see Status
  // Where a stop-and-flag report is POSTed besides the console, for
  // unattended runs. Best-effort: a failed delivery is reported, never
  // fatal, and never replaces the console record.
  escalation: { webhookUrl: process.env.FARKETARI_ESCALATION_WEBHOOK },
};

export default config;
```

The file is loaded with Node's native type stripping (Node >= 22.18):
erasable TypeScript only, and the type-only `farketari` import works
before the package is installed. `farketari.ts` holds facts about how
farketari works on this project; facts about the app itself stay in the
project's own global configuration.

## Templates

Templates are self-describing: a template repository carries
`farketari/template.json` declaring its name, clients, layout, command
catalog, bootstrap rules, and optional per-work-kind prompt overrides
(markdown files in the template — override only what your stack changes,
inherit the rest). The CLI loads the descriptor from the `--example`
path; without one it falls back to the built-in nextjs-fastify
configuration. Adding a stack (Vue or plain React instead of Next.js,
say) means writing its example and skeleton under `stacks/` plus a
descriptor — farketari itself does not change.

The loader validates before it trusts: every layout path, bootstrap
rule, prompt override, and `{example}` citation must exist in the
checkout. Run it in template CI:

```sh
farketari validate-template <template-path>
```

Porting the tool to another project means editing configuration, not the
algorithm: `RepoLayout` (where things live), `CommandCatalog` (what may be
executed, including the remote-runner vocabulary), `PromptCatalog` (the
per-work-kind instructions), and `ModelConfiguration` (which model runs
which kind of work). Role implementations plug in through the
`ImplementFeatureDeps` container; `stubRole` covers the ones you have not
built yet.

## Authentication & billing

farketari holds no credentials. Each AI step runs as a Claude Code
session (`claude-step.ts`) that authenticates from the environment, the
same chain the `claude` CLI uses: the stored `claude login`, or
`CLAUDE_CODE_OAUTH_TOKEN` (mint one with `claude setup-token` for
CI/headless machines).

Sessions are **subscription-first**: for Anthropic-native backends,
`claudeStep` drops an exported `ANTHROPIC_API_KEY` from the session's
environment so runs bill the logged-in subscription, never silently the
API. Export `FARKETARI_USE_API_KEY=1` to deliberately use the API key
instead. Backends with a `baseUrl` (the routed easy tier) keep their
environment untouched — their auth belongs to the router (typically
`ANTHROPIC_AUTH_TOKEN` or a key the router holds). Secrets never go in
`farketari.ts`; the config carries URLs and names, the environment
carries tokens.

## License

MIT
