@supporterino/ai-factory 0.0.0-stage → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +106 -0
- package/LICENSE +21 -0
- package/README.md +226 -2
- package/dist/cli.js +38298 -0
- package/dist/package.json +3 -0
- package/package.json +61 -4
- package/templates/addons/ponytail/LICENSE +21 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes per release. `ai-factory update` applies them to an installed workspace (see [docs/cli.md](docs/cli.md#update)).
|
|
4
|
+
|
|
5
|
+
## 0.3.0
|
|
6
|
+
|
|
7
|
+
### Minor Changes
|
|
8
|
+
|
|
9
|
+
- 7d6bb18: Add config schema v3: project instructions, skills and MCP permissions, custom agents with path routing, per-repo and per-agent models, conditional/generated gates, generated/CRD/IPC/custom contracts, Swift, `refine`/`run --interactive`, `quick`, gitmoji commits, legacy setup archiving and release/CI detection. Existing v2 configs keep working and `update` migrates them to v3.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- c0937d5: Ship `dist/package.json` with the CLI bundle so Node 20 parses `dist/cli.js` as ESM instead of failing with `Cannot use import statement outside a module`.
|
|
14
|
+
|
|
15
|
+
## 0.2.0
|
|
16
|
+
|
|
17
|
+
### Breaking (handled by `update`)
|
|
18
|
+
|
|
19
|
+
- Config `schemaVersion` 2. Migration `001-graph-exclude-defaults` replaces the default `graph.exclude` list with the wider v2 default (adds `vendor`, `build`, `coverage`, `.next`, `__pycache__`). A customised list is kept as is. Commands refuse a v1 config until you run `ai-factory update`.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- `ai-factory update [--dry-run] [--tools] [--restore] [--force]`: config migrations, three-way merge of edited managed files, a backup per update and one `chore(factory): update to vX.Y.Z` commit.
|
|
24
|
+
- `ai-factory rollback`: restores the latest update backup, including the previous lock.
|
|
25
|
+
- Approving a change snapshots its agent definitions and gate tables, so a forced update never changes a running change.
|
|
26
|
+
- `docs/fleet-update.sh`: an example for updating many workspaces.
|
|
27
|
+
- Tauri v2 language profile (`tauri`). It is detected from `tauri.conf.json`/`Tauri.toml` next to a `tauri` 2.x dependency. It runs the cargo gates in `src-tauri/` instead of the Rust profile (which also validates capabilities and the config), creates a missing `frontendDist` directory before compiling, and comes with its own standard. Existing workspaces get `.opencode/standards/tauri.md` on `update`; run `detect --apply` to add `tauri` to a repo.
|
|
28
|
+
- `ai-factory doctor`: checks tool versions and lock drift, the install, submodules, clean trees, hooks, the resolved gate table with toolchain lookup, cache sizes, model availability, graph freshness and stale locks.
|
|
29
|
+
- `README.md`, `ARCHITECTURE.md`, and E2E transcripts per layout in `docs/e2e/`, recorded with real opencode and a scripted model (`scripts/e2e-transcript.ts`).
|
|
30
|
+
|
|
31
|
+
### Distribution
|
|
32
|
+
|
|
33
|
+
- The npm package is now `@supporterino/ai-factory`. The unscoped `ai-factory` on npm is an unrelated project. Run it with `npx @supporterino/ai-factory@0.2.0 init`; the command is still `ai-factory`.
|
|
34
|
+
- MIT LICENSE added.
|
|
35
|
+
- `prepack` builds the bundle, and the package ships only the bundle, docs and licences.
|
|
36
|
+
- GitHub Actions CI runs the full suite on Ubuntu and macOS; releases publish from `main` with provenance and create a GitHub Release.
|
|
37
|
+
- `init`, `update` and `detect --apply` refuse to downgrade a workspace a newer version installed (`--allow-downgrade` to override).
|
|
38
|
+
|
|
39
|
+
### Security
|
|
40
|
+
|
|
41
|
+
- **Second hardening batch (S11, S14–S17, S19).**
|
|
42
|
+
- Secret files can no longer be read through globs, `git show <rev>:.env`, recursive `grep -r`/`rg --hidden`, inline code or the grep/glob tools; on macOS agent shells cannot read workspace secrets at all (gates still can). The two secret lists agree and cover `~/.kube/*.yaml`.
|
|
43
|
+
- `npm run`/`pnpm`/`yarn`/`bun run` scripts and `make` recipes are checked like the commands they run; concatenated strings in other languages are joined before scanning.
|
|
44
|
+
- Implementers and testers cannot edit `openspec/`. Patches the plugin cannot read are refused.
|
|
45
|
+
- Redaction covers auth headers, bearer tokens, `-u user:pass` and URL tokens, runs before JSON escaping, applies to gate output, and `logs.redact: false` no longer turns off credential redaction.
|
|
46
|
+
- Untrusted text is fenced so it cannot close its fence; edit and patch contents are not logged.
|
|
47
|
+
|
|
48
|
+
- **Shell-policy and git hardening.** Fixes all enforcement bypasses from the 2026-10-26 audit (S1–S10, S12):
|
|
49
|
+
- shell keywords and `cd` are parsed and tracked;
|
|
50
|
+
- xargs, interpreter, awk/sed and runner evasions are closed;
|
|
51
|
+
- git env, `-c` keys and exec options are restricted; `fetch` refspecs and agent commits are blocked;
|
|
52
|
+
- writes are judged on real paths (symlinks), more writers are covered, and protected paths match case-insensitively.
|
|
53
|
+
- **Every shell spawn is guarded.** opencode's `shell create.before` hook only spawns approved commands and scrubs the server password, model keys and forge tokens. Non-factory agents and opencode's REST shell are refused.
|
|
54
|
+
- **OS sandbox (macOS `sandbox-exec`).**
|
|
55
|
+
- Covers agent shells and gates.
|
|
56
|
+
- Writes are limited to the session's own directories; run state, factory files and `.git` stay read-only.
|
|
57
|
+
- Credential files and git credential helpers are off-limits, and ssh (port 22) is blocked.
|
|
58
|
+
- New config key `security.sandbox` (`"auto"` | `"off"`).
|
|
59
|
+
- **Gates and installs.** Both run without credentials and with pushes blocked. A task may not change the scripts or targets its gates run.
|
|
60
|
+
|
|
61
|
+
### Changed: language standards
|
|
62
|
+
|
|
63
|
+
- Every standard (TypeScript, React, Python, Go, Rust, Helm, Tauri) is rewritten from its primary docs, e.g. Effective Go and Go Code Review Comments, the TypeScript Handbook's Do's and Don'ts, react.dev's Rules of React, PEP 8/257 and the typing best practices, the Rust API Guidelines, Helm's chart best practices and the Pod Security Standards, and the v2.tauri.app security and IPC guides.
|
|
64
|
+
- Each standard lists its sources in an HTML comment, cites them per section, and marks factory-specific rules (such as Rust unit tests in a sibling `tests.rs`, which keeps them within the tester's edit scope). Comments are stripped from agent prompts.
|
|
65
|
+
- Corrections: Tauri app commands need no capability unless they are listed in `AppManifest::commands`; Tauri state uses `std::sync::Mutex` by default, with no `Arc`.
|
|
66
|
+
|
|
67
|
+
### Fixed
|
|
68
|
+
|
|
69
|
+
- **Retries.** Every retry gets the full gate output; repeated failures no longer arrive as an empty note (audit P1).
|
|
70
|
+
- **Abort.** `abort` stops a change in every phase, interrupts running agents, frees the workspace when the driver stops, and `resume` continues the change (P2).
|
|
71
|
+
- **Branching.** If branching fails after intake, the next run branches first; the spec is only ever committed on `change/<id>` (P3).
|
|
72
|
+
- **Merges.** A task whose conflict was resolved while another task merged now catches up instead of failing (P4).
|
|
73
|
+
- **Server crashes.** A crashed opencode server is restarted. Server failures never spend retry budget, and the change pauses after three in a row (P5).
|
|
74
|
+
- **OpenSpec files.** OpenSpec's opencode commands and skills are managed files: `init` and `update --tools` no longer overwrite your edits (P19).
|
|
75
|
+
- **Approval.** A spec edited after approval is caught on entry to every later phase, not only at activation; the error shows how to restore the approved spec (P9).
|
|
76
|
+
- **Reviews.** A reviewer or contract reviewer that returns no result pauses the change instead of counting as a clean review (P13).
|
|
77
|
+
- **Close.** Closing records each step, so a resume after a crash finishes the close instead of failing (P6).
|
|
78
|
+
- **Concurrent drivers.** Every phase after approval takes the driver lock, so two `resume`s cannot run a review or close twice; `approve` re-checks the phase under the run lock (P14).
|
|
79
|
+
- **Corrupt state files.** A corrupt run file, `active.lock` or `queue.json` gives a clear error with a fix; `status` and `doctor` list it instead of crashing (P15). A corrupt usage ledger is set aside and a new one started; unreadable graph metadata is ignored.
|
|
80
|
+
- **Budget.** Ctrl-C during a merge or a conflict resolution spends nothing and keeps the branch (P7). After a crash, tasks that already passed their gates go straight to the merge (P8). A provider that stays rate-limited, and a failed dependency install, pause the change instead of spending budget; installs are retried, also in kept worktrees (P12, P16).
|
|
81
|
+
- **Serial mode.** Work a failed task left in the shared checkout is stashed under its name, not reverted and charged to the next task (P10).
|
|
82
|
+
- **Queue.** A queued change resumed by hand leaves the queue, so it is not started a second time and the next change still auto-starts (P11).
|
|
83
|
+
- **Snapshots.** Agent and gate definitions are fixed at `approve`, not at activation (P18). `update` never commits onto a `change/*` branch, even with `--force`, so a running change keeps its agents in every session (P17, G7). `gate <id>` uses the change's snapshot (G9).
|
|
84
|
+
- **Smaller gaps (P20).** Context packs and the spec in review/test prompts are capped at a whole line; one failing explorer no longer sinks the design; graph updates take a workspace lock; a submodule branches from the newer of its local and fetched base branch.
|
|
85
|
+
- **`init`** keeps an existing `openspec/config.yaml` and lists it as unmanaged (G2). **`detect --apply`** merges edited implementer agents and never leaves a half-applied config (G3).
|
|
86
|
+
- **`update --restore`** repairs tampered or deleted vendored Ponytail files (G5). `--tools` also rebuilds a graph built by another Graphify release; a plain `update` warns about it (G6). `--dry-run --json` lists paths, not file contents (G9).
|
|
87
|
+
- **Helm** types gate fails when `helm template` fails (G8). Monorepo packages' languages bring their standards and test globs (G9). Design validation requires consumer tasks to depend on contract changes, and rejects invalid `touches` globs (G9).
|
|
88
|
+
- **Handoffs.** A reply without any JSON is reported as a missing block, not a parse error.
|
|
89
|
+
|
|
90
|
+
- The architect and tester agents get edit permissions for their own paths (change and context folders, test globs). Before, opencode's permission layer denied their writes.
|
|
91
|
+
- Closing a change removes its agent snapshot and empty worktree folders, and `status` no longer lists the snapshot as a worktree.
|
|
92
|
+
- Full-suite gate results are written to the change's log.
|
|
93
|
+
|
|
94
|
+
### Changed
|
|
95
|
+
|
|
96
|
+
- `bench ponytail` has two cases (a new function and a fix in existing code), `--case` and `--levels` options, medians of quality metrics over finished runs only, and saves results after every run (G1). It has still not been run on real models.
|
|
97
|
+
- `status` shows full-suite results, contract results and provisional pointers; reports list usage per task and step (G4).
|
|
98
|
+
- `doctor` warns about a non-strict `tsconfig.json`, a graph built by another Graphify release, and proxy variables, and checks Graphify's safety env.
|
|
99
|
+
- ADR-0028 records the default models, time limits and rate-limit parameters.
|
|
100
|
+
|
|
101
|
+
- Implementer agents: a rule for merge-conflict tasks (change only the conflicted files, keep both intents).
|
|
102
|
+
- `AGENTS.md` block: query the workspace graph before reading files.
|
|
103
|
+
|
|
104
|
+
## 0.1.0
|
|
105
|
+
|
|
106
|
+
First release: `init`, `detect`, `gate`, `repoint`, `run`, `approve`, `resume`, `status`, `retry`, `abort`, `graph` and `bench`. Includes the OpenSpec workflow, the Graphify workspace graph, the opencode agents and plugin guard, the contract gate and the Ponytail add-on.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lars Roth
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,227 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ai-factory
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://github.com/supporterino/ai-factory/actions/workflows/ci.yml)
|
|
4
|
+
|
|
5
|
+
A repo-local AI software factory. You describe a change; the factory writes an [OpenSpec](https://github.com/Fission-AI/OpenSpec) spec, waits for your approval, then has [opencode](https://opencode.ai) agents implement, test and review it across your repos, guided by one [Graphify](https://pypi.org/project/graphifyy/) knowledge graph of the workspace.
|
|
6
|
+
- **One human gate:** the spec approval. Everything after it runs on its own, and pauses with a report when it cannot finish.
|
|
7
|
+
- **Local commits only.** Nothing is pushed and no merge request is opened. You review the `change/<id>` branches and push them yourself.
|
|
8
|
+
- **Two layouts:** a single repo, or an "AI repo" that holds your code repos as git submodules.
|
|
9
|
+
- **Language profiles** (stackable per repo): TypeScript/JavaScript, React, Python, Go, Rust, Swift, Helm, Tauri v2.
|
|
10
|
+
|
|
11
|
+
How it works inside: [ARCHITECTURE.md](ARCHITECTURE.md). Every command: [docs/cli.md](docs/cli.md). Design decisions: [docs/decisions/](docs/decisions/). Changes per version: [CHANGELOG.md](CHANGELOG.md).
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
Requirements: macOS or Linux, Node ≥ 20 or Bun ≥ 1.3, and these tools on `PATH`:
|
|
16
|
+
|
|
17
|
+
| Tool | Version | Install |
|
|
18
|
+
| -------- | ---------------- | -------------------------------------------------- |
|
|
19
|
+
| git | ≥ 2.31 | Xcode CLT or your package manager |
|
|
20
|
+
| opencode | 2.1.x (≥ 2.1.2) | `npm install --global @opencode/cli@2.1.2` |
|
|
21
|
+
| OpenSpec | 1.x (≥ 1.10) | `npm install --global @fission-ai/openspec@1.14.3` |
|
|
22
|
+
| Graphify | 0.9.x (≥ 0.9.93) | `uv tool install graphifyy==0.9.93` |
|
|
23
|
+
|
|
24
|
+
Plus credentials for the model providers you configure, either exported (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, …) or stored with `opencode auth login`.
|
|
25
|
+
|
|
26
|
+
Run the CLI without installing it:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
bunx @supporterino/ai-factory@0.3.0 init
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`npx @supporterino/ai-factory@0.3.0 init` works too. The package is `@supporterino/ai-factory`; its command is `ai-factory`, so after `npm install --global @supporterino/ai-factory` you run `ai-factory init`. Note: the unscoped npm package `ai-factory` is an unrelated project. To run it from a checkout of this repository instead, build it with `bun install && bun run build`, then run `node dist/cli.js` (or `npm link` it).
|
|
33
|
+
|
|
34
|
+
`init` is idempotent. It detects the layout, languages, contracts and existing `opencode.json` instructions, and writes `factory.config.jsonc` from what it found, so edit that file afterwards. It also renders the agents, plugin, standards, skills and OpenSpec's commands into `.opencode/`, installs the `pre-push` hooks, builds the graph, writes `factory.lock.json`, and commits it all as `chore(factory): init vX.Y.Z`. On a first install it archives replaced custom agents, commands and skills under `.factory/legacy/<timestamp>/`; `init --plan` shows that plan without writing. Then check the setup:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
ai-factory doctor
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`doctor` prints the resolved gate command per repo and flags anything a run would trip over: a missing toolchain, a model your credentials can't reach, a missing hook, an uninitialised submodule.
|
|
41
|
+
|
|
42
|
+
## Layouts
|
|
43
|
+
|
|
44
|
+
**Single repo.** The factory lives in the repo itself (`repos: [{ "path": "." }]`). Agents may never edit the factory's own files (`.opencode/`, `.factory/`, `openspec/specs/`, the config, the lock, `AGENTS.md`), even though they sit in the same tree.
|
|
45
|
+
|
|
46
|
+
**AI repo with submodules.** A repo that holds the factory and your code repos as submodules:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
ai-repo/
|
|
50
|
+
├── factory.config.jsonc, factory.lock.json, AGENTS.md
|
|
51
|
+
├── .opencode/ agents (one implementer per repo), plugin, standards
|
|
52
|
+
├── openspec/ specs and changes
|
|
53
|
+
└── repos/
|
|
54
|
+
├── backend/ submodule (go, OpenAPI provider)
|
|
55
|
+
├── frontend/ submodule (typescript + react, consumer)
|
|
56
|
+
└── deploy/ submodule (helm)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The same `change/<id>` branch is created in the AI repo and in every submodule the change touches. Task worktrees are created from each submodule's own git dir. At close, the AI repo gets a provisional pointer bump; `repoint` replaces it once your merge requests are merged upstream. Contracts between repos (OpenAPI, JSON Schema, Helm `values.schema.json`, proto) are checked by a deterministic gate plus one cross-repo review.
|
|
60
|
+
|
|
61
|
+
## The flow
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
ai-factory run "Add full-text search to the product list"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
1. **Intake and design.** The orchestrator names the change. Explorers map the affected repos using the graph. The architect writes `openspec/changes/<id>/` (proposal, design, specs and `tasks.md`, with per-task `repo`/`deps`/`touches`). The CLI validates it and has the architect repair problems. `run` stops here.
|
|
68
|
+
2. **Approve.** Read the spec, edit it if you like, then:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
ai-factory approve <id>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
This commits the spec (`docs(spec): <id>`) and records its hash. Any later edit to the spec, other than a task checkbox, voids the approval. If another change is active, this one queues and starts automatically when the other one closes. Use `--no-continue` to only record the approval.
|
|
75
|
+
3. **Implement.** Tasks run in parallel in their own worktrees, at most `maxAgents` at a time. Tasks in one repo whose `touches` overlap run one after the other. Each task gets an affected-test gate. Merges go through a per-repo queue: rebase, gates again, fast-forward. A failing task gets three retries, then the change pauses with a report.
|
|
76
|
+
4. **Review, contracts, full suite.** Each touched repo gets one reviewer and one tester pass. Then come the contract gate and contract review, and finally every touched repo's full suite. Findings and failures become fix tasks.
|
|
77
|
+
5. **Close.** The CLI mirrors the checkboxes, bumps the pointers, archives the spec and writes the report to `.factory/reports/<id>.md`. It makes local commits only.
|
|
78
|
+
|
|
79
|
+
While it runs, or after it stops:
|
|
80
|
+
|
|
81
|
+
| Situation | Command |
|
|
82
|
+
| ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
|
|
83
|
+
| See what is happening: phase, task DAG, worktrees, gate results, token usage | `ai-factory status [<id>] [--json]` |
|
|
84
|
+
| It paused because a task failed three times: fix it in the task's worktree (path in the report), then | `ai-factory retry <id> --task <n>` |
|
|
85
|
+
| It paused, was aborted, or the process died: continue from the last consistent state | `ai-factory resume <id>` |
|
|
86
|
+
| Stop it safely (branches and worktrees stay, the lock is released) | `ai-factory abort <id>` |
|
|
87
|
+
| Run the gates by hand | `ai-factory gate <id> [--task <n>] [--repo <name>] [--full]` |
|
|
88
|
+
| Your submodule MRs were merged upstream: replace the provisional pointers | `ai-factory repoint <id>` |
|
|
89
|
+
|
|
90
|
+
Exit codes: 0 ok, 3 config invalid, 4 precondition, 5 gate failed, 6 paused/aborted, 10 detection drift ([full table](docs/cli.md#exit-codes)).
|
|
91
|
+
|
|
92
|
+
### Refinement and quick tasks
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
ai-factory refine "make the imports faster" # ask scope/verification questions, write .factory/requests/<slug>.md
|
|
96
|
+
ai-factory run --request .factory/requests/make-the-imports-faster.md
|
|
97
|
+
ai-factory run "make the imports faster" --interactive
|
|
98
|
+
ai-factory quick "fix the login typo" --repo frontend # add --agent <id> for a custom implementer
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`refine` and `run --interactive` ask a few questions before the architect sees the request; spec approval is still the only hard gate. `quick` is the no-OpenSpec path: it creates a `task/<slug>` branch, implements, runs the gates, runs one review pass, and makes one local commit. It never pushes.
|
|
102
|
+
|
|
103
|
+
## Configuration reference
|
|
104
|
+
|
|
105
|
+
`factory.config.jsonc` (JSONC, validated on every command; the editor schema is `.opencode/schemas/factory.config.schema.json`):
|
|
106
|
+
|
|
107
|
+
| Key | Default | Meaning |
|
|
108
|
+
| ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
109
|
+
| `$schema` | `./.opencode/schemas/factory.config.schema.json` | JSON Schema for editor completion and checks; the factory keeps it current. |
|
|
110
|
+
| `schemaVersion` | `3` | Config format. `ai-factory update` migrates older ones; v2 stays readable until you update. |
|
|
111
|
+
| `layout` | detected | `"single"` or `"submodules"`. |
|
|
112
|
+
| `repos[]` | detected | `{ name, path, role: "code" \| "orchestration", languages[], defaultBranch?, subPaths?[] }`.`languages` stacks profiles (`typescript`, `react`, `python`, `go`, `rust`, `swift`, `helm`, `tauri`). A Tauri v2 app is detected as `typescript` (plus `react`) for the frontend and `rust` + `tauri` for `src-tauri/`, where the `tauri` profile runs the cargo gates. `subPaths` overrides languages for monorepo packages. In the submodule layout, the AI repo is the one `orchestration` repo at `"."`. |
|
|
113
|
+
| `models.{orchestrator, architect, reviewer, contractReviewer?, implementer, tester, explorer}` | Opus for architect/reviewer, Sonnet for orchestrator/implementer/tester, Haiku for explorer | opencode ids `"provider/model[#variant]"`.`contractReviewer` falls back to `reviewer`.`models.roles`, `models.repos.<repo>` and `models.agents.<id>` override the flat entries; `fallback[]` lists alternates. |
|
|
114
|
+
| `instructions.{workspace, repos.<repo>}` | `[]`, `{}` | Project docs (security bars, language bars, API contracts) injected into opencode sessions. The reviewer/tester prompts also name them. |
|
|
115
|
+
| `skills.{sources, roles, repos}` | `[".opencode/skills"]`, `{}`, `{}` | Skill ids each role loads first; the skill tool is enabled for those roles. `sources` is where `doctor` looks for `SKILL.md`. |
|
|
116
|
+
| `mcp.roles.<role>` | `{}` | MCP tool action patterns a role may call (e.g. `["mantine_*"]`). Without an entry MCP tools stay on `ask`, which headless runs reject. |
|
|
117
|
+
| `agents[]`, `routing[]` | `[]`, `[]` | Optional specialist agents (`id`, `phase`, `prompt` or `promptFile`, `model`, `skills`, `edits`, `shell`, `web`, `mcp`) and path-to-agent routing for implementation tasks. |
|
|
118
|
+
| `gates.maxRetries` | `3` | Retries per task after the first attempt. |
|
|
119
|
+
| `gates.scripts` | `format:check`, `lint`, `typecheck`, `test`, `test:affected` | Script or target names looked up in `package.json`, `Makefile`, `justfile` and `Taskfile.yml`. |
|
|
120
|
+
| `gates.overrides.<repo>.<gate>` | `{}` | A literal command, which wins over scripts and profile defaults. `"skip"` turns that gate off. Placeholders: `{files}`, `{testFiles}`, `{packages}`, `{crates}`, `{charts}`, `{base}`. |
|
|
121
|
+
| `gates.extra[]` | `[]` | Conditional gates: `name`, `type`, `phases`, `when.changed`, `command`, `env`, `setup`, `outputs`, `checkOnly`, `timeoutMs`.`outputs` makes it a generated-artifact drift gate. |
|
|
122
|
+
| `contracts[]` | detected | `{ kind: openapi \| proto \| json-schema \| helm-values \| generated \| crd \| ipc \| custom, provider, path, consumers[], command?, outputs?, allowBreaking?, validate?{<consumer>: cmd} }`.`generated`/`crd`/`ipc` contracts run their command and fail on output drift. In `validate` commands, `{contract}` is the absolute path of the provider's new contract. |
|
|
123
|
+
| `commits.{style, scopes}` | `"conventional"`, `false` | `"gitmoji"` keeps the Conventional prefix and adds the emoji; `scopes` adds the repo name to task commits. |
|
|
124
|
+
| `workflow.{refine, quick}` | `true`, `{enabled: true, branchPrefix: "task/"}` | Enables `refine` / `run --interactive` and `ai-factory quick`. |
|
|
125
|
+
| `release.detect` | `true` | Detects release-please, goreleaser, changesets and forge CI, and reports them in `doctor`; no workflow is edited. |
|
|
126
|
+
| `parallel.maxAgents` | `4` | Concurrent agent sessions. |
|
|
127
|
+
| `parallel.maxGateProcesses` | `2` | Concurrent gate processes. |
|
|
128
|
+
| `parallel.withinRepo` | `"worktrees"` | `"serial"` runs one task per repo at a time. |
|
|
129
|
+
| `tokens.contextPackMaxTokens` | `8000` | Cap on each task's context pack. |
|
|
130
|
+
| `tokens.gateOutputMaxLines` | `80` | Compacted gate output fed back to agents. |
|
|
131
|
+
| `tokens.mode` | `"report"` | Usage is reported, never enforced. |
|
|
132
|
+
| `addons.ponytail.{enabled, ref, roles, level, shortcutComments}` | `true`, pinned ref, `["implementer","reviewer"]`, `"full"`, `"report"` | See [Ponytail](#ponytail). |
|
|
133
|
+
| `logs.retentionDays` | `14` | How long logs are kept. |
|
|
134
|
+
| `logs.redact` | `true` | Redacts secrets from the logs. |
|
|
135
|
+
| `graph.exclude` | node_modules, vendor, target, dist, build, coverage, .next, `__pycache__`, .venv, .factory, graphify-out | Paths the graph skips. |
|
|
136
|
+
| `security.sandbox` | `"auto"` | Run agent shells and gates in an OS sandbox: macOS `sandbox-exec` when present. It blocks writes outside the session's worktree, edits to rc and git files, reads of credential files, git credential helpers and ssh. `"off"` disables it. Other platforms have no sandbox yet; `doctor` warns. |
|
|
137
|
+
| `unmanaged[]` | `[]` | Managed files you want to own completely: `update` never touches them. |
|
|
138
|
+
|
|
139
|
+
You can edit the agents in `.opencode/agents/` and the standards in `.opencode/standards/`. `update` merges your edits with new templates. `detect` shows drift between the workspace and the config, and `detect --apply` adds new repos' implementers, scopes and hooks.
|
|
140
|
+
|
|
141
|
+
## Updating
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
bunx @supporterino/ai-factory@<new> update --dry-run # print the plan
|
|
145
|
+
bunx @supporterino/ai-factory@<new> update # one commit: chore(factory): update to vX.Y.Z
|
|
146
|
+
bunx @supporterino/ai-factory@<new> rollback # undo it
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`update` migrates the config while keeping your comments. It replaces managed files you didn't touch, merges three-way the ones you edited (a conflict leaves markers and commits nothing), and keeps deleted files deleted unless `--restore`. `--tools` also refreshes OpenSpec's files and rebuilds the graph if its format changed. It refuses while a change is in progress unless `--force`; a running change keeps the agent and gate definitions it was approved with. For many workspaces, see [docs/fleet-update.sh](docs/fleet-update.sh).
|
|
150
|
+
|
|
151
|
+
## Ponytail
|
|
152
|
+
|
|
153
|
+
[Ponytail](https://github.com/DietrichGebert/ponytail) (minimal-code guidance) is vendored at `v5.3.2@16352ac2`, verified by content hash, and injected only into implementer and reviewer prompts. The factory's rules and your standards take precedence over it. `shortcutComments: "report"` collects `shortcut:` comments into the report, and `"forbid"` fails the gate on them.
|
|
154
|
+
|
|
155
|
+
**Default.** `enabled: true` is provisional. `ai-factory bench ponytail` compares runs with and without it on your models: tokens, diff size, first-attempt pass rate, retries, coverage and review findings. It writes the result to `docs/bench/`. The bench makes real model calls, so it prints a cost estimate and asks first. It has not been run for this release yet, and the default will be set from its result.
|
|
156
|
+
|
|
157
|
+
## Troubleshooting
|
|
158
|
+
|
|
159
|
+
| Symptom | Fix |
|
|
160
|
+
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
161
|
+
| `uses config schemaVersion 1; this factory needs 3` | `ai-factory update` (it migrates v1 → v2 → v3 and keeps comments). |
|
|
162
|
+
| `doctor`: `model … is not available to opencode` | The server only sees the credentials of providers named in `models`. Export the provider's key (e.g. `ANTHROPIC_API_KEY`) or run `opencode auth login`, or change the model. |
|
|
163
|
+
| `doctor` / `gate`: `no format gate` or `not found: golangci-lint` | Install the tool, add a script under the name in `gates.scripts`, or set `gates.overrides.<repo>.<gate>` (`"skip"` to turn it off). |
|
|
164
|
+
| `gate is not check-only` | Your format or lint script writes files. Point the gate at the check variant (e.g. `prettier --check`, `biome check`). |
|
|
165
|
+
| The change paused | Read `.factory/reports/<id>.md`. Fix the code in the named worktree, then run `retry <id> --task <n>`; or run `resume <id>` after a transient failure. |
|
|
166
|
+
| `the spec changed after approval` | Something other than a checkbox changed in `openspec/changes/<id>/`. Review it, then run `approve <id>` again. |
|
|
167
|
+
| `<id> is the active change` after a crash | `ai-factory resume <id>` takes over the stale lock (or `abort <id>`). `doctor` shows locks that nothing is driving. |
|
|
168
|
+
| `update` stopped with conflicts | Resolve the `<<<<<<< yours` markers in the listed files and commit, or `ai-factory rollback`. |
|
|
169
|
+
| `Ponytail add-on files were modified` | `ai-factory update --restore`, or set `addons.ponytail.enabled` to `false`. |
|
|
170
|
+
| A push is rejected by the `ai-factory` pre-push hook | It blocks pushes from agents while a change is active. Push from your own shell, where `AI_FACTORY_AGENT` is not set. |
|
|
171
|
+
| Tauri: `cargo check` fails on a permission "not found" | A capability in `src-tauri/capabilities/` names a permission the app doesn't have. Add the plugin (`tauri add <plugin>`) or fix the identifier. |
|
|
172
|
+
| Tauri gates fail on Linux with missing `webkit2gtk`/`pkg-config` libraries | Install Tauri's Linux prerequisites on the machine that runs the gates. |
|
|
173
|
+
| An agent's command fails with `Operation not permitted` | The macOS sandbox stopped a write outside the session's worktree, or a read of a credential file. Agents work inside their worktree. If a repo truly needs more, set `security.sandbox` to `"off"` (weaker guarantees; see ADR-0026). |
|
|
174
|
+
| A task fails with "you changed how your work is checked" | It edited a script or target the gates run (e.g. `scripts.lint` in package.json). Change gate definitions yourself, outside a factory change. |
|
|
175
|
+
| A submodule is missing or empty | `ai-factory doctor` offers `git submodule update --init`. |
|
|
176
|
+
| Commits fail with a signing error | The factory commits with your git config. Unlock your signing agent (e.g. 1Password) and run `resume`, or rerun the command. |
|
|
177
|
+
| Agents re-read the same files a lot | `status` shows wasted re-reads. Build the graph (`ai-factory graph`) so agents can query it instead. |
|
|
178
|
+
|
|
179
|
+
Logs: `.factory/logs/<id>/` (redacted tool calls and gate results). Run state: `.factory/runs/<id>.json`.
|
|
180
|
+
|
|
181
|
+
## Adding a language profile
|
|
182
|
+
|
|
183
|
+
A profile is the language's prose standard plus a machine-readable part: test globs, markers, gate commands and install steps.
|
|
184
|
+
1. Add the id to `LANGUAGES` in `src/config/schema.ts`. Enum additions need no config migration, and the editor JSON schema is generated from it.
|
|
185
|
+
2. Add detection in `src/detect/languages.ts`: the manifest or marker files that imply it.
|
|
186
|
+
3. Write `templates/standards/<id>.md` from the language's primary docs:
|
|
187
|
+
- a `<!-- Sources: [key] Title — URL -->` block under the title;
|
|
188
|
+
- a `## Summary` of standalone bullets (they go into `AGENTS.md`);
|
|
189
|
+
- under each section, a `<!-- [key] … -->` comment naming what grounds it, and `<!-- factory -->` after rules that come from the factory rather than a source.
|
|
190
|
+
|
|
191
|
+
A test enforces the citations. The comments are stripped from agent prompts.
|
|
192
|
+
4. Add the profile to `PROFILES` in `src/profiles/index.ts`:
|
|
193
|
+
- `testGlobs`: what the tester may edit;
|
|
194
|
+
- `markers` and `targets`: where gates run;
|
|
195
|
+
- `extensions` and `binDirs`;
|
|
196
|
+
- `gates`: per gate type, candidates in preference order, with optional `when` requirements and `scoped` per-task variants;
|
|
197
|
+
- `install`: lockfile → command;
|
|
198
|
+
- `supersedes` (optional): profiles whose target in the same directory this one replaces. The Tauri profile replaces Rust in `src-tauri/`, for example.
|
|
199
|
+
5. If its package manager has a cache, add it to `cacheEnv` in `src/gates/install.ts`.
|
|
200
|
+
6. Add tests: detection (`test/detect-units.test.ts`) and gate resolution (`test/gates-resolve.test.ts`).
|
|
201
|
+
7. Add a changeset with `bun run changeset` (a user-facing change needs a release note). Workspaces pick up the new standard and their regenerated implementers with `ai-factory update`, then `ai-factory detect --apply` adds the language to the repos that use it.
|
|
202
|
+
|
|
203
|
+
## Development
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
bun install
|
|
207
|
+
bun run check # biome + tsc + bun test
|
|
208
|
+
bun run build # dist/cli.js and the bundled plugin
|
|
209
|
+
bun run changeset # record a release note for this PR
|
|
210
|
+
AI_FACTORY_E2E=1 bun test test/opencode-runtime.e2e.test.ts # real opencode, stub model server
|
|
211
|
+
bun scripts/e2e-transcript.ts single # re-record docs/e2e/single.md (also: submodules)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
The test suite builds fixture workspaces in temp dirs: a single TS repo, and an AI repo with Go, React and Helm submodules. It stubs the LLM with scripted handoffs. The manual end-to-end runs in [docs/e2e/](docs/e2e/) drive the real opencode server, git, OpenSpec, Graphify and gate toolchains, with a scripted role-aware model, so they cost nothing and can be reproduced. See ADR-0023 for what they cover and what they don't.
|
|
215
|
+
|
|
216
|
+
CI runs the full suite on Ubuntu and macOS, then smoke-tests the npm tarball and the built bundle on Node 20.3, 22 and 24. The manual `E2E` workflow runs the real-opencode runtime test against the pinned opencode version.
|
|
217
|
+
|
|
218
|
+
### Releasing
|
|
219
|
+
|
|
220
|
+
Changesets owns the version and the changelog. Release tooling runs on Node 24; the published CLI still supports Node >=20.3.
|
|
221
|
+
1. Create `release/vX.Y.Z` from `main`.
|
|
222
|
+
2. Run `bun run release:version`. It applies the pending changesets, writes `CHANGELOG.md`, syncs `src/version.ts` and regenerates the install snapshot.
|
|
223
|
+
3. Review the changelog and the version files, then run `bun run check`.
|
|
224
|
+
4. Commit, push and open a normal PR. CI runs on it.
|
|
225
|
+
5. Merge the PR. The release workflow re-runs the checks, publishes the new version to npm with provenance, and creates the `X.Y.Z` GitHub Release and tag with the tarball attached.
|
|
226
|
+
|
|
227
|
+
The `npm` environment should require a reviewer. Merging a version PR is the release action; branch protection and tag protection are part of the process. Publishing is disabled until the repository variable `RELEASE_ENABLED` is `true`. The first publish is manual because npm trusted publishing requires an existing package; set the variable after publishing 0.2.0 and configuring the trusted publisher. On npm, configure workflow `release.yml`, environment `npm`, and allow direct `npm publish` (not stage-only). `package.json`'s `repository.url` must match the GitHub repository exactly. See ADR-0029.
|