farketari
v0.43.0
Published
Feature-implementation algorithm for ATDD/DDD projects built on the nextjs-fastify stack architecture.
Maintainers
Readme
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, 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— thebootstrapcommand, end to end.escalationTo— stop-and-flag to the console, and toescalation.webhookUrlwhen a project configures one.bootstrapProject+fileBootstrapper— the older, model-driven bootstrap specified in bootstrap.md, which strips a full example down to its architecture (what survives isbootstrap-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: —
" 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_GITLAB_TOKEN or GITLAB_TOKEN with read_api in the
environment — absent, it throws with instructions 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
farketari implement <feature-file> [--example <path>] [--tdd] [--instructions <text>]
farketari bootstrap <target-dir> --name <project-name> --stack <name>
[--stack-version <version>] [--ref <ref>] [--repo <url>]
farketari validate-template <template-path>implement
<feature-file>— the.featurefile 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 unlessfarketari.tssetsexampleProjectSource, 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 standingrunInstructions.
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 (defaultv1).--ref <ref>— branch, tag or commit of the stacks repository; pin a tag for a reproducible start (defaultmain).--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.
Library
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. 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:
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:
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
