ndomo 0.1.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/.bun-version +1 -0
- package/.dockerignore +79 -0
- package/.editorconfig +18 -0
- package/.env.example +19 -0
- package/.github/CODEOWNERS +8 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +62 -0
- package/.github/ISSUE_TEMPLATE/config.yml +2 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +34 -0
- package/.github/dependabot.yml +36 -0
- package/.github/pull_request_template.md +24 -0
- package/.github/release.yml +30 -0
- package/.github/workflows/gitleaks.yml +28 -0
- package/.github/workflows/release-please.yml +27 -0
- package/.github/workflows/smoke.yml +29 -0
- package/.husky/commit-msg +1 -0
- package/CHANGELOG.md +114 -0
- package/Dockerfile +32 -0
- package/README.es.md +174 -0
- package/README.md +187 -0
- package/agents/chronicler.md +98 -0
- package/agents/ci-smith.md +136 -0
- package/agents/craftsman.md +341 -0
- package/agents/deploy-smith.md +138 -0
- package/agents/foreman.md +377 -0
- package/agents/go-smith.md +164 -0
- package/agents/guild.md +188 -0
- package/agents/inspector.md +83 -0
- package/agents/js-smith.md +127 -0
- package/agents/ops-scout.md +173 -0
- package/agents/painter.md +200 -0
- package/agents/python-smith.md +120 -0
- package/agents/ranger.md +307 -0
- package/agents/release-smith.md +165 -0
- package/agents/rust-smith.md +159 -0
- package/agents/sage.md +178 -0
- package/agents/scout.md +144 -0
- package/agents/scribe.md +156 -0
- package/agents/smith.md +201 -0
- package/agents/vue-smith.md +155 -0
- package/agents/warden.md +216 -0
- package/agents/zig-smith.md +156 -0
- package/bin/ndomo-analyses.ts +4 -0
- package/bin/ndomo-status.ts +4 -0
- package/biome.json +57 -0
- package/bun.lock +514 -0
- package/commitlint.config.js +3 -0
- package/config/ndomo.config.json +258 -0
- package/config/ndomo.schema.json +166 -0
- package/docs/agents.md +375 -0
- package/docs/bugs/plan-create-orphan-fk.md +131 -0
- package/docs/bugs/task_create_batch-order-index-collision.md +158 -0
- package/docs/configuration.md +276 -0
- package/docs/database.md +364 -0
- package/docs/features/feature-flexible-builder-v1.md +724 -0
- package/docs/features/feature-flexible-builder-v2.md +882 -0
- package/docs/features/feature-flexible-builder.md +974 -0
- package/docs/http-server.md +244 -0
- package/docs/installation.md +259 -0
- package/docs/integrations.md +129 -0
- package/docs/operations/anti-pattern-sub-agent-verify-2026-06-21.md +32 -0
- package/docs/operations/audit-v1.md +417 -0
- package/docs/operations/audit-v2.md +197 -0
- package/docs/operations/audit-v3.md +306 -0
- package/docs/operations/db-optimize-foundations.md +123 -0
- package/docs/operations/verify-gate-architecture.md +82 -0
- package/docs/workflows.md +448 -0
- package/opencode.json +5 -0
- package/package.json +65 -0
- package/release-please-config.json +11 -0
- package/scripts/dev-bust-cache.sh +164 -0
- package/scripts/install.sh +688 -0
- package/scripts/smoke-e2e.ts +704 -0
- package/scripts/smoke-hot.ts +417 -0
- package/scripts/smoke-http.sh +228 -0
- package/scripts/smoke-v4.ts +256 -0
- package/scripts/smoke-v5.ts +397 -0
- package/scripts/smoke.sh +9 -0
- package/scripts/uninstall.sh +224 -0
- package/skills/api-security-best-practices/SKILL.md +915 -0
- package/skills/bash-scripting/SKILL.md +201 -0
- package/skills/bun/SKILL.md +313 -0
- package/skills/cavecrew/SKILL.md +82 -0
- package/skills/caveman/SKILL.md +74 -0
- package/skills/caveman-review/README.md +33 -0
- package/skills/caveman-review/SKILL.md +55 -0
- package/skills/find-skills/SKILL.md +142 -0
- package/skills/frontend-design/LICENSE.txt +177 -0
- package/skills/frontend-design/SKILL.md +55 -0
- package/skills/golang-patterns/SKILL.md +674 -0
- package/skills/golang-security/SKILL.md +185 -0
- package/skills/golang-security/evals/evals.json +595 -0
- package/skills/golang-security/references/architecture.md +268 -0
- package/skills/golang-security/references/checklist.md +80 -0
- package/skills/golang-security/references/cookies.md +200 -0
- package/skills/golang-security/references/cryptography.md +424 -0
- package/skills/golang-security/references/filesystem.md +285 -0
- package/skills/golang-security/references/injection.md +315 -0
- package/skills/golang-security/references/logging.md +163 -0
- package/skills/golang-security/references/memory-safety.md +241 -0
- package/skills/golang-security/references/network.md +253 -0
- package/skills/golang-security/references/secrets.md +189 -0
- package/skills/golang-security/references/third-party.md +159 -0
- package/skills/golang-security/references/threat-modeling.md +189 -0
- package/skills/golang-testing/SKILL.md +720 -0
- package/skills/grill-me/SKILL.md +7 -0
- package/skills/javascript-testing-patterns/SKILL.md +537 -0
- package/skills/javascript-testing-patterns/references/advanced-testing-patterns.md +513 -0
- package/skills/modern-javascript-patterns/SKILL.md +43 -0
- package/skills/modern-javascript-patterns/references/advanced-patterns.md +487 -0
- package/skills/modern-javascript-patterns/references/details.md +457 -0
- package/skills/python-anti-patterns/SKILL.md +349 -0
- package/skills/python-design-patterns/SKILL.md +85 -0
- package/skills/python-design-patterns/references/details.md +353 -0
- package/skills/python-error-handling/SKILL.md +193 -0
- package/skills/python-error-handling/references/details.md +171 -0
- package/skills/python-testing-patterns/SKILL.md +278 -0
- package/skills/python-testing-patterns/references/advanced-patterns.md +411 -0
- package/skills/python-testing-patterns/references/details.md +349 -0
- package/skills/rust-patterns/SKILL.md +500 -0
- package/skills/rust-testing/SKILL.md +501 -0
- package/skills/security-review/SKILL.md +504 -0
- package/skills/security-review/cloud-infrastructure-security.md +361 -0
- package/skills/vue-best-practices/SKILL.md +154 -0
- package/skills/vue-best-practices/references/animation-class-based-technique.md +254 -0
- package/skills/vue-best-practices/references/animation-state-driven-technique.md +291 -0
- package/skills/vue-best-practices/references/component-async.md +97 -0
- package/skills/vue-best-practices/references/component-data-flow.md +307 -0
- package/skills/vue-best-practices/references/component-fallthrough-attrs.md +174 -0
- package/skills/vue-best-practices/references/component-keep-alive.md +137 -0
- package/skills/vue-best-practices/references/component-slots.md +216 -0
- package/skills/vue-best-practices/references/component-suspense.md +228 -0
- package/skills/vue-best-practices/references/component-teleport.md +108 -0
- package/skills/vue-best-practices/references/component-transition-group.md +128 -0
- package/skills/vue-best-practices/references/component-transition.md +125 -0
- package/skills/vue-best-practices/references/composables.md +290 -0
- package/skills/vue-best-practices/references/directives.md +162 -0
- package/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +159 -0
- package/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +182 -0
- package/skills/vue-best-practices/references/perf-virtualize-large-lists.md +187 -0
- package/skills/vue-best-practices/references/plugins.md +166 -0
- package/skills/vue-best-practices/references/reactivity.md +344 -0
- package/skills/vue-best-practices/references/render-functions.md +201 -0
- package/skills/vue-best-practices/references/sfc.md +310 -0
- package/skills/vue-best-practices/references/state-management.md +135 -0
- package/skills/vue-best-practices/references/updated-hook-performance.md +187 -0
- package/skills/vue-pinia-best-practices/SKILL.md +21 -0
- package/skills/vue-pinia-best-practices/reference/pinia-no-active-pinia-error.md +248 -0
- package/skills/vue-pinia-best-practices/reference/pinia-setup-store-return-all-state.md +227 -0
- package/skills/vue-pinia-best-practices/reference/pinia-store-destructuring-breaks-reactivity.md +193 -0
- package/skills/vue-pinia-best-practices/reference/state-url-for-ephemeral-filters.md +238 -0
- package/skills/vue-pinia-best-practices/reference/state-use-pinia-for-large-apps.md +262 -0
- package/skills/vue-pinia-best-practices/reference/store-method-binding-parentheses.md +191 -0
- package/skills/zig-0.16/SKILL.md +840 -0
- package/skills/zig-0.16/scripts/check-zig-version.sh +21 -0
- package/src/cli/analyses.ts +280 -0
- package/src/cli/index.ts +108 -0
- package/src/cli/serve.ts +192 -0
- package/src/cli/smoke.ts +131 -0
- package/src/cli/status.test.ts +204 -0
- package/src/cli/status.ts +263 -0
- package/src/cli/vacuum.test.ts +82 -0
- package/src/cli/vacuum.ts +96 -0
- package/src/config/schema.test.ts +88 -0
- package/src/config/schema.ts +64 -0
- package/src/db/analyses-migration.test.ts +210 -0
- package/src/db/analyses.test.ts +466 -0
- package/src/db/analyses.ts +375 -0
- package/src/db/auto-checkpoint.ts +131 -0
- package/src/db/client.test.ts +129 -0
- package/src/db/client.ts +55 -0
- package/src/db/fts-escape.ts +20 -0
- package/src/db/incidents.test.ts +201 -0
- package/src/db/incidents.ts +93 -0
- package/src/db/index.ts +86 -0
- package/src/db/migrations-v13.test.ts +141 -0
- package/src/db/migrations-v8.test.ts +301 -0
- package/src/db/migrations.ts +147 -0
- package/src/db/plan-archive.test.ts +180 -0
- package/src/db/plan-archive.ts +274 -0
- package/src/db/plan-create.test.ts +276 -0
- package/src/db/plan-create.ts +78 -0
- package/src/db/plan-files.test.ts +289 -0
- package/src/db/plan-update-status.ts +287 -0
- package/src/db/plans.test.ts +490 -0
- package/src/db/plans.ts +534 -0
- package/src/db/resolve-project-dir.test.ts +143 -0
- package/src/db/resolve-project-dir.ts +75 -0
- package/src/db/rollbacks.test.ts +150 -0
- package/src/db/rollbacks.ts +67 -0
- package/src/db/schema.ts +907 -0
- package/src/db/sessions.test.ts +80 -0
- package/src/db/sessions.ts +135 -0
- package/src/db/shutdown.test.ts +147 -0
- package/src/db/shutdown.ts +45 -0
- package/src/db/tasks.test.ts +921 -0
- package/src/db/tasks.ts +747 -0
- package/src/db/types.ts +619 -0
- package/src/http/__tests__/auth.test.ts +196 -0
- package/src/http/__tests__/routes.test.ts +465 -0
- package/src/http/__tests__/sse.test.ts +317 -0
- package/src/http/auth.ts +72 -0
- package/src/http/middleware/cors.ts +53 -0
- package/src/http/middleware/security-headers.ts +21 -0
- package/src/http/routes/events.ts +112 -0
- package/src/http/routes/health.ts +51 -0
- package/src/http/routes/plans.ts +66 -0
- package/src/http/routes/sessions.ts +50 -0
- package/src/http/routes/tasks.ts +60 -0
- package/src/http/server.ts +95 -0
- package/src/http/sse.ts +116 -0
- package/src/index.ts +37 -0
- package/src/lib.ts +65 -0
- package/src/mem/scoped.ts +65 -0
- package/src/orchestrator/background.test.ts +268 -0
- package/src/orchestrator/background.ts +293 -0
- package/src/orchestrator/memory-hook.ts +182 -0
- package/src/orchestrator/reconciler.ts +123 -0
- package/src/orchestrator/scheduler.test.ts +300 -0
- package/src/orchestrator/scheduler.ts +243 -0
- package/src/plugin.test.ts +2574 -0
- package/src/plugin.ts +1690 -0
- package/src/sdk/client.ts +66 -0
- package/src/worktrees/manager.ts +236 -0
- package/src/worktrees/state.ts +87 -0
- package/tests/integration/ranger-flow.test.ts +257 -0
- package/tools/analysis_archive.ts +28 -0
- package/tools/analysis_create.ts +55 -0
- package/tools/analysis_get.ts +33 -0
- package/tools/analysis_link_plan.ts +44 -0
- package/tools/analysis_list.ts +48 -0
- package/tools/analysis_search.ts +36 -0
- package/tools/analysis_update.ts +44 -0
- package/tools/plan_approve.ts +31 -0
- package/tools/plan_create.ts +58 -0
- package/tools/plan_get.ts +40 -0
- package/tools/plan_list.ts +37 -0
- package/tools/plan_search.ts +34 -0
- package/tools/plan_update_status.ts +71 -0
- package/tools/session_checkpoint.ts +31 -0
- package/tools/session_end.ts +26 -0
- package/tools/session_start.ts +43 -0
- package/tools/task_create_batch.ts +70 -0
- package/tools/task_list.ts +35 -0
- package/tools/task_next_for_agent.ts +30 -0
- package/tools/task_search.ts +34 -0
- package/tools/task_update_status.ts +37 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# Configuration Reference
|
|
2
|
+
|
|
3
|
+
## Config File Location
|
|
4
|
+
|
|
5
|
+
`~/.config/opencode/ndomo.json`
|
|
6
|
+
|
|
7
|
+
The schema is defined in `config/ndomo.schema.json` (JSON Schema draft-07) for editor validation.
|
|
8
|
+
|
|
9
|
+
## Presets
|
|
10
|
+
|
|
11
|
+
These presets are the source of truth for agent models at install time. The installer rewrites each agent's `model:` and `temperature:` from the active preset on every install.
|
|
12
|
+
|
|
13
|
+
Two built-in presets control which models each agent uses.
|
|
14
|
+
|
|
15
|
+
### Per-agent fields
|
|
16
|
+
|
|
17
|
+
Each agent entry in a preset supports three fields:
|
|
18
|
+
|
|
19
|
+
| Field | Type | Required | Description |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| `model` | string | yes | Model identifier in `provider/model-id` format |
|
|
22
|
+
| `temperature` | number (0-1) | yes | Sampling temperature (0 = deterministic, 1 = creative) |
|
|
23
|
+
| `reasoning_effort` | enum: `low`/`medium`/`high`/`xhigh` | no | Reasoning effort level for reasoning-capable models (DeepSeek, MiMo, OpenAI). Translated to camelCase `reasoningEffort:` in agent `.md` frontmatter. Omit for non-reasoning models. |
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"presets": {
|
|
29
|
+
"default": {
|
|
30
|
+
"smith": {
|
|
31
|
+
"model": "opencode-go/deepseek-v4-flash",
|
|
32
|
+
"temperature": 0.1,
|
|
33
|
+
"reasoning_effort": "medium"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### default
|
|
41
|
+
|
|
42
|
+
| Agent | Model | Temperature |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| foreman | minimax/MiniMax-M3 | 0.3 |
|
|
45
|
+
| scout | opencode-go/minimax-m2.7 | 0.3 |
|
|
46
|
+
| scribe | opencode-go/minimax-m2.7 | 0.3 |
|
|
47
|
+
| painter | opencode-go/kimi-k2.6 | 0.2 |
|
|
48
|
+
| smith | opencode-go/deepseek-v4-flash | 0.1 |
|
|
49
|
+
| ranger | minimax/MiniMax-M3 | 0.3 |
|
|
50
|
+
| sage | opencode-go/deepseek-v4-pro | 0.2 |
|
|
51
|
+
| guild | opencode-go/deepseek-v4-pro | 0.3 |
|
|
52
|
+
| go-smith | xiaomi/mimo-v2.5-pro | 0.1 |
|
|
53
|
+
| js-smith | xiaomi/mimo-v2.5-pro | 0.1 |
|
|
54
|
+
| python-smith | xiaomi/mimo-v2.5-pro | 0.1 |
|
|
55
|
+
| vue-smith | xiaomi/mimo-v2.5-pro | 0.1 |
|
|
56
|
+
| zig-smith | xiaomi/mimo-v2.5-pro | 0.1 |
|
|
57
|
+
| chronicler | opencode-go/deepseek-v4-flash | 0.2 |
|
|
58
|
+
| inspector | opencode-go/deepseek-v4-pro | 0.2 |
|
|
59
|
+
|
|
60
|
+
### budget
|
|
61
|
+
|
|
62
|
+
All agents use `opencode-go/deepseek-v4-flash` at their respective temperatures. Reduces API costs at the expense of specialist model quality for stack-smiths and advisors.
|
|
63
|
+
|
|
64
|
+
## Provider Override at Install Time
|
|
65
|
+
|
|
66
|
+
The `install.sh` script includes a provider override that modifies agent models before registration. This is not a runtime setting — it applies once during installation and is baked into each agent's frontmatter.
|
|
67
|
+
|
|
68
|
+
The preset (not the provider) defines the model ID. `--provider=ID` only changes the `provider/` prefix in each agent's `model:` field, so the literal `default` model ID is never used.
|
|
69
|
+
|
|
70
|
+
### How it works
|
|
71
|
+
|
|
72
|
+
1. Without `--provider` and without `--no-provider-prompt`, the script shows the active preset and asks for confirmation.
|
|
73
|
+
2. Selecting `override` enters the interactive provider picker from models.dev.
|
|
74
|
+
3. The selected provider prefix replaces the existing `provider/` segment in every agent's `model:` field in `agents/*.md`.
|
|
75
|
+
|
|
76
|
+
### Example transformation
|
|
77
|
+
|
|
78
|
+
If you override with provider `opencode`, the agent models transform as follows:
|
|
79
|
+
|
|
80
|
+
| Original | After provider prefix override |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `minimax/MiniMax-M3` | `opencode/MiniMax-M3` (provider prefix changed) |
|
|
83
|
+
| `opencode-go/deepseek-v4-flash` | `opencode/deepseek-v4-flash` (provider prefix changed) |
|
|
84
|
+
| `xiaomi/mimo-v2.5-pro` | `opencode/mimo-v2.5-pro` (provider prefix changed) |
|
|
85
|
+
|
|
86
|
+
### Flags controlling provider override
|
|
87
|
+
|
|
88
|
+
| Flag | Behavior |
|
|
89
|
+
|---|---|
|
|
90
|
+
| `--provider=ID` | Non-interactive provider prefix override. The model ID is taken from the active preset; only the `provider/` segment of the `model:` field is swapped. |
|
|
91
|
+
| `--no-provider-prompt` | Skips the interactive picker. The preset is still applied; no prefix override is performed. |
|
|
92
|
+
|
|
93
|
+
The install also wires the plugin into the OpenCode config directory (`~/.config/opencode/`) so tools are auto-registered on OpenCode launch — see [plugin docs](https://opencode.ai/docs/es/plugins/) and [custom tools docs](https://opencode.ai/docs/es/custom-tools/).
|
|
94
|
+
|
|
95
|
+
### Relevant files modified
|
|
96
|
+
|
|
97
|
+
- `agents/*.md` — the `model:` field in each agent's frontmatter is modified during Step 5.5 of the install script.
|
|
98
|
+
- `~/.cache/ndomo/models-catalog.json` — cached catalog (re-fetched weekly or on cache miss).
|
|
99
|
+
|
|
100
|
+
The provider override is a one-time install operation. To change providers after installation, either re-run `install.sh` with a different `--provider` flag, or manually edit the `model:` fields in `agents/*.md`.
|
|
101
|
+
|
|
102
|
+
## Hot-swap: editing models without re-running install
|
|
103
|
+
|
|
104
|
+
`ndomo.json::presets[preset][agent].model` is the **runtime source of truth** for agent models. The plugin's `syncAgentFrontmatter()` runs at every OpenCode session startup, compares each agent's `model:` and `temperature:` in `~/.config/opencode/agent/<agent>.md` against the active preset in `ndomo.json`, and rewrites the file when the values differ. This means you can edit `ndomo.json` directly and have the changes take effect on the next session — no need to re-run `install.sh`.
|
|
105
|
+
|
|
106
|
+
**Workflow:**
|
|
107
|
+
|
|
108
|
+
1. Open `~/.config/opencode/ndomo.json`.
|
|
109
|
+
2. Edit `presets[default|...][<agent-name>].model` and/or `.temperature`. Example:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"preset": "default",
|
|
114
|
+
"presets": {
|
|
115
|
+
"default": {
|
|
116
|
+
"foreman": { "model": "anthropic/claude-sonnet-4.5", "temperature": 0.3 }
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
3. Restart OpenCode. The plugin logs `[ndomo] frontmatter sync: preset=default synced=N skipped=M errors=0` on startup.
|
|
123
|
+
|
|
124
|
+
**Notes:**
|
|
125
|
+
|
|
126
|
+
- Only agents present in the active preset are synced. User-added custom agents (not in `ndomo.json`) are left untouched.
|
|
127
|
+
- The function is **idempotent** — running it with an unchanged config is a no-op (`skipped=N, synced=0`).
|
|
128
|
+
- To disable hot-swap (e.g., for read-only configs or CI), set env var `NDOMO_SKIP_FRONTMATTER_SYNC=1` before launching OpenCode.
|
|
129
|
+
- If the active preset is missing from `ndomo.json` (e.g., `"preset": "production"` but only `default` and `budget` are defined), sync is skipped with a warning — agent files keep their current values.
|
|
130
|
+
- `reasoning_effort` syncing supports both updating an existing `reasoningEffort:` line and inserting a new one (placed after `temperature:`, then `model:`, then `---` as fallback).
|
|
131
|
+
|
|
132
|
+
## Agent Routing
|
|
133
|
+
|
|
134
|
+
The `agentRouting` field defines the delegation graph. Four agents are defined as `mode: "primary"` peer primaries: `foreman` (planner/orchestrator), `craftsman` (implementer), `warden` (ops custodian), and `ranger` (analyst/cartographer/onboarding). All other agents are subagents reachable via the primaries' `delegates_to` arrays. The foreman's `delegates_to` array lists all subagents it can dispatch.
|
|
135
|
+
|
|
136
|
+
**Ranger** is the 4th primary, registered separately with `mode: "primary"` and its own delegation graph (`scout`, `sage`, `scribe`). Unlike foreman/craftsman/warden, ranger does not create plans — it produces rows in the `analyses` DB table linkable retroactively via `analysis_link_plan`.
|
|
137
|
+
|
|
138
|
+
Routing decisions are made by the scheduler (`src/orchestrator/scheduler.ts`):
|
|
139
|
+
|
|
140
|
+
| Task type | Stack | Risk | Routed to |
|
|
141
|
+
|---|---|---|---|
|
|
142
|
+
| explore | any | any | scout |
|
|
143
|
+
| research | any | any | scribe |
|
|
144
|
+
| design | vue | any | painter |
|
|
145
|
+
| audit | any | any | inspector |
|
|
146
|
+
| document | any | any | chronicler |
|
|
147
|
+
| debate | any | any | guild |
|
|
148
|
+
| debug | any | high | sage |
|
|
149
|
+
| implement | go | any | go-smith |
|
|
150
|
+
| implement | vue | any | vue-smith |
|
|
151
|
+
| implement | js | any | js-smith |
|
|
152
|
+
| implement | python | any | python-smith |
|
|
153
|
+
| implement | zig | any | zig-smith |
|
|
154
|
+
| implement | generic/unknown | any | smith |
|
|
155
|
+
| implement | known stack | high | stack-smith + sage advisory |
|
|
156
|
+
| any other | any | any | smith (fallback) |
|
|
157
|
+
|
|
158
|
+
## Caveman Settings
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"caveman": {
|
|
163
|
+
"intensity": "full",
|
|
164
|
+
"autoClarity": true
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
| Field | Type | Values | Description |
|
|
170
|
+
|---|---|---|---|
|
|
171
|
+
| `intensity` | string | `lite`, `full`, `ultra` | Compression level. `lite` keeps some articles; `full` strips all fillers; `ultra` maximum compression. |
|
|
172
|
+
| `autoClarity` | boolean | `true`, `false` | When `true`, agents switch to full verbosity for safety warnings, irreversible actions, or multi-step ambiguity, then resume caveman. |
|
|
173
|
+
|
|
174
|
+
## DCP Overrides
|
|
175
|
+
|
|
176
|
+
Per-agent context limits for the DCP plugin. Only takes effect when `@tarquinen/opencode-dcp` is installed.
|
|
177
|
+
|
|
178
|
+
```json
|
|
179
|
+
{
|
|
180
|
+
"dcp_overrides": {
|
|
181
|
+
"scout": { "minContextLimit": 30000, "maxContextLimit": 80000 },
|
|
182
|
+
"scribe": { "minContextLimit": 30000, "maxContextLimit": 80000 },
|
|
183
|
+
"foreman": { "minContextLimit": 50000, "maxContextLimit": 100000 },
|
|
184
|
+
"sage": { "minContextLimit": 50000, "maxContextLimit": 100000 },
|
|
185
|
+
"guild": { "minContextLimit": 50000, "maxContextLimit": 100000 },
|
|
186
|
+
"inspector": { "minContextLimit": 40000, "maxContextLimit": 90000 },
|
|
187
|
+
"ranger": { "minContextLimit": 50000, "maxContextLimit": 100000 }
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Agents without explicit overrides use DCP defaults. The foreman monitors context size and triggers compression when approaching `maxContextLimit`.
|
|
193
|
+
|
|
194
|
+
## Memory Config
|
|
195
|
+
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"mem": {
|
|
199
|
+
"storagePath": "~/.ndomo/mem",
|
|
200
|
+
"defaultScope": "project",
|
|
201
|
+
"autoCaptureEnabled": true,
|
|
202
|
+
"cavemanCompress": true
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
| Field | Type | Description |
|
|
208
|
+
|---|---|---|
|
|
209
|
+
| `storagePath` | string | Directory for opencode-mem storage only. Does NOT control plan archive location. Supports `~` expansion. |
|
|
210
|
+
| `defaultScope` | string | `"project"` — search only current project memories; `"all-projects"` — search across all projects. |
|
|
211
|
+
| `autoCaptureEnabled` | boolean | Automatically capture insights during sessions without explicit `memory({mode:"add"})` calls. |
|
|
212
|
+
| `cavemanCompress` | boolean | Apply caveman regex compression to memories before storage. Saves tokens on retrieval. |
|
|
213
|
+
|
|
214
|
+
> **Note:** `~/.ndomo/mem/` is the **opencode-mem** plugin's storage (USearch
|
|
215
|
+
> vector DB for semantic memory). The **ndomo plugin's** database is at
|
|
216
|
+
> `<project>/.ndomo/state.db` (SQLite) — see [docs/database.md](docs/database.md).
|
|
217
|
+
> These are two separate systems; both can run simultaneously.
|
|
218
|
+
>
|
|
219
|
+
> **Plan archive path:** The ndomo plugin auto-archives completed/failed plans
|
|
220
|
+
> to `<project>/.ndomo/archives/plans/<slug>-YYYY-MM-DD.md` (markdown snapshots).
|
|
221
|
+
> This path is **not configurable** via `ndomo.json` — it always lives under
|
|
222
|
+
> `<project>/.ndomo/archives/plans/`. See [docs/database.md#auto-archive](docs/database.md#auto-archive).
|
|
223
|
+
|
|
224
|
+
## Protected Tools
|
|
225
|
+
|
|
226
|
+
Tools listed in `protectedTools` cannot be disabled, overridden, or pruned from context by any subagent:
|
|
227
|
+
|
|
228
|
+
```json
|
|
229
|
+
"protectedTools": ["memory", "compress", "task", "todowrite", "skill"]
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
| Tool | Why Protected |
|
|
233
|
+
|---|---|
|
|
234
|
+
| `memory` | Required for cross-session persistence and context retrieval |
|
|
235
|
+
| `compress` | Required for DCP context pruning when near token limits |
|
|
236
|
+
| `task` | Required for subagent delegation and background dispatch |
|
|
237
|
+
| `todowrite` | Required for structured task tracking |
|
|
238
|
+
| `skill` | Required for loading agent skill definitions |
|
|
239
|
+
|
|
240
|
+
## Troubleshooting
|
|
241
|
+
|
|
242
|
+
### Tools not registered / DB not created
|
|
243
|
+
|
|
244
|
+
The ndomo package is not in `~/.config/opencode/node_modules/ndomo/`. OpenCode's plugin loader silently skips plugins it cannot resolve, so no tools, DB, or agents will appear.
|
|
245
|
+
|
|
246
|
+
**Fix:** Re-run `./scripts/install.sh` or symlink it manually:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
ln -sfn $(pwd) ~/.config/opencode/node_modules/ndomo
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Then ensure `ndomo` is listed in `opencode.json` under `plugins`. See [plugin docs](https://opencode.ai/docs/es/plugins/) for details.
|
|
253
|
+
|
|
254
|
+
## Custom Agents
|
|
255
|
+
|
|
256
|
+
To add a custom agent to the routing table:
|
|
257
|
+
|
|
258
|
+
1. Create an agent definition file in `agents/<name>.md` with frontmatter:
|
|
259
|
+
```yaml
|
|
260
|
+
---
|
|
261
|
+
description: My custom agent
|
|
262
|
+
mode: subagent
|
|
263
|
+
model: provider/model-id
|
|
264
|
+
temperature: 0.1
|
|
265
|
+
permission:
|
|
266
|
+
edit: allow
|
|
267
|
+
bash: allow
|
|
268
|
+
question: allow
|
|
269
|
+
---
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
2. Add the agent to the foreman's `delegates_to` array in `config/ndomo.config.json`.
|
|
273
|
+
|
|
274
|
+
3. Add a routing rule in `src/orchestrator/scheduler.ts` or rely on the Foreman prompt routing table.
|
|
275
|
+
|
|
276
|
+
4. Optionally add a model entry in the `default` and `budget` presets.
|
package/docs/database.md
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
# Database & Plans
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
ndomo persists plans, tasks, and sessions in a project-local SQLite database
|
|
6
|
+
located at `<project>/.ndomo/state.db` (`src/db/client.ts:12-13`). Created
|
|
7
|
+
automatically on first plugin load via `openDb(projectDir)` (`src/db/client.ts:15-20`).
|
|
8
|
+
Survives OpenCode restarts. Indexed with FTS5 for full-text search.
|
|
9
|
+
|
|
10
|
+
### What gets stored
|
|
11
|
+
|
|
12
|
+
- **Plans** — long-running initiatives with a slug, status (draft/approved/executing/completed/failed/abandoned),
|
|
13
|
+
priority (1-4), complexity (1-5), category, and audit trail
|
|
14
|
+
- **Tasks** — atomic units of work assigned to a specific agent, with
|
|
15
|
+
dependencies (by order_index), result/error fields, and artifacts
|
|
16
|
+
- **Sessions** — continuity across agent dispatches, with checkpoints,
|
|
17
|
+
agent history, and key decisions
|
|
18
|
+
|
|
19
|
+
### What is NOT stored here
|
|
20
|
+
|
|
21
|
+
- `~/.ndomo/mem/` is the **opencode-mem** plugin's storage (USearch vector DB
|
|
22
|
+
for semantic memory, configured via `ndomo.json` `mem.storagePath`)
|
|
23
|
+
- `docs/plans/<slug>.md` is the **opencode-planning-toolkit** markdown storage
|
|
24
|
+
(different system, simpler, git-friendly)
|
|
25
|
+
- The ndomo DB archive output goes to `<project>/.ndomo/archives/plans/` (markdown snapshots)
|
|
26
|
+
|
|
27
|
+
## Schema
|
|
28
|
+
|
|
29
|
+
### Tables
|
|
30
|
+
|
|
31
|
+
#### `plans`
|
|
32
|
+
|
|
33
|
+
| Column | Type | Notes |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `id` | TEXT PK | UUID v4 |
|
|
36
|
+
| `slug` | TEXT UNIQUE | kebab-case, 1-60 chars, validated via trigger (`src/db/schema.ts:257-268`) |
|
|
37
|
+
| `title` | TEXT | Short actionable phrase |
|
|
38
|
+
| `status` | TEXT | CHECK: `draft`, `approved`, `executing`, `completed`, `failed`, `abandoned` |
|
|
39
|
+
| `priority` | INTEGER | 1-4, validated via trigger (`src/db/schema.ts:244-254`) |
|
|
40
|
+
| `created_at` | INTEGER | Epoch ms |
|
|
41
|
+
| `updated_at` | INTEGER | Auto-updated via trigger (`src/db/schema.ts:205-209`) |
|
|
42
|
+
| `approved_at` | INTEGER | Null until approved |
|
|
43
|
+
| `completed_at` | INTEGER | Null until terminal status |
|
|
44
|
+
| `session_id` | TEXT | FK to sessions (app-level validation, `src/db/plans.ts:118-121`) |
|
|
45
|
+
| `overview` | TEXT | 2-4 line description |
|
|
46
|
+
| `approach` | TEXT | Implementation strategy |
|
|
47
|
+
| `complexity` | INTEGER | 1-5 |
|
|
48
|
+
| `metadata` | JSON | Discriminated via `PlanMetadata` type |
|
|
49
|
+
| `created_by` | TEXT | Agent name |
|
|
50
|
+
| `updated_by` | TEXT | Agent name |
|
|
51
|
+
| `source_session_id` | TEXT | Originating session |
|
|
52
|
+
| `source_message_id` | TEXT | Originating message ID |
|
|
53
|
+
| `category` | TEXT | CHECK: `feature`, `refactor`, `bugfix`, `docs`, `infra` |
|
|
54
|
+
| `archived_at` | INTEGER | Null when active, epoch ms when archived (v5 soft delete) |
|
|
55
|
+
|
|
56
|
+
Indexes: `idx_plans_status`, `idx_plans_session`, `idx_plans_created`,
|
|
57
|
+
`idx_plans_status_priority`, `idx_plans_archived`.
|
|
58
|
+
|
|
59
|
+
#### `plan_tasks`
|
|
60
|
+
|
|
61
|
+
| Column | Type | Notes |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `id` | TEXT PK | UUID v4 |
|
|
64
|
+
| `plan_id` | TEXT FK | References `plans(id)` ON DELETE CASCADE |
|
|
65
|
+
| `order_index` | INTEGER | Sequential within plan. UNIQUE(plan_id, order_index) |
|
|
66
|
+
| `description` | TEXT | Task description |
|
|
67
|
+
| `agent` | TEXT | Assigned agent name |
|
|
68
|
+
| `files` | JSON | Expected output files `[]` |
|
|
69
|
+
| `complexity` | INTEGER | 1-5 |
|
|
70
|
+
| `status` | TEXT | CHECK: `pending`, `running`, `done`, `failed`, `blocked` |
|
|
71
|
+
| `started_at` | INTEGER | Epoch ms, set when `running` |
|
|
72
|
+
| `completed_at` | INTEGER | Epoch ms, set when `done` or `failed` |
|
|
73
|
+
| `result` | TEXT | Free text, truncated to 16KB (`src/db/tasks.ts:109-121`) |
|
|
74
|
+
| `error` | TEXT | Error message, truncated to 16KB |
|
|
75
|
+
| `dependencies` | JSON | Array of order_index values |
|
|
76
|
+
| `metadata` | JSON | Discriminated via `TaskMetadata` type, default `'{}'` |
|
|
77
|
+
| `created_by` | TEXT | Agent name |
|
|
78
|
+
| `updated_by` | TEXT | Agent name |
|
|
79
|
+
| `source_session_id` | TEXT | Originating session |
|
|
80
|
+
| `source_message_id` | TEXT | Originating message ID |
|
|
81
|
+
| `reviewed_by` | TEXT | Reviewer agent name |
|
|
82
|
+
| `tokens_used` | INTEGER | Token count for this task |
|
|
83
|
+
| `duration_ms` | INTEGER | Execution duration |
|
|
84
|
+
| `artifacts` | JSON | Array of artifact paths |
|
|
85
|
+
| `archived_at` | INTEGER | Null when active (v5 soft delete) |
|
|
86
|
+
|
|
87
|
+
Indexes: `idx_tasks_plan`, `idx_tasks_status`, `idx_tasks_agent`,
|
|
88
|
+
`idx_tasks_plan_status`, `idx_tasks_agent_status`, `idx_tasks_archived`.
|
|
89
|
+
|
|
90
|
+
#### `sessions`
|
|
91
|
+
|
|
92
|
+
| Column | Type | Notes |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| `id` | TEXT PK | UUID v4 |
|
|
95
|
+
| `started_at` | INTEGER | Epoch ms |
|
|
96
|
+
| `ended_at` | INTEGER | Null until ended |
|
|
97
|
+
| `last_checkpoint` | INTEGER | Updated by `checkpointSession()` via trigger (`src/db/schema.ts:218-223`) |
|
|
98
|
+
| `plan_id` | TEXT | References `plans(id)` ON DELETE SET NULL |
|
|
99
|
+
| `goal` | TEXT | Session goal description |
|
|
100
|
+
| `state` | JSON | Arbitrary checkpoint state `{}` |
|
|
101
|
+
| `agent_history` | JSON | Array of `{agent, taskId, startedAt, endedAt}` |
|
|
102
|
+
| `key_decisions` | TEXT | Free text decision log |
|
|
103
|
+
| `metadata` | JSON | Discriminated via `SessionMetadata` type |
|
|
104
|
+
| `created_by` | TEXT | Agent name |
|
|
105
|
+
| `source_message_id` | TEXT | Originating message ID |
|
|
106
|
+
| `parent_session_id` | TEXT | Self-referencing FK |
|
|
107
|
+
| `outcome` | TEXT | CHECK: `success`, `partial`, `failed`, `abandoned` |
|
|
108
|
+
| `archived_at` | INTEGER | Null when active (v5 soft delete) |
|
|
109
|
+
|
|
110
|
+
Indexes: `idx_sessions_started`, `idx_sessions_plan`, `idx_sessions_archived`.
|
|
111
|
+
|
|
112
|
+
### FTS5 indexes
|
|
113
|
+
|
|
114
|
+
- **`plans_fts_v2`** — content=`plans` (external), columns `id` (UNINDEXED), `title`,
|
|
115
|
+
`overview`, `approach`, `category`. Tokenizer: `unicode61 remove_diacritics 1`.
|
|
116
|
+
Auto-synced via `AFTER INSERT/UPDATE/DELETE` triggers (`src/db/schema.ts:441-463`).
|
|
117
|
+
- **`tasks_fts`** — content=`plan_tasks` (external), columns `id` (UNINDEXED), `description`,
|
|
118
|
+
`result`, `error`. Same tokenizer. Auto-synced via triggers (`src/db/schema.ts:345-363`).
|
|
119
|
+
|
|
120
|
+
Query escaping: `escapeFtsQuery()` wraps user input in double quotes to prevent
|
|
121
|
+
FTS5 syntax injection from hyphens and special characters (`src/db/fts-escape.ts:18-19`).
|
|
122
|
+
|
|
123
|
+
### Tag tables (M:N)
|
|
124
|
+
|
|
125
|
+
- **`plan_tags(plan_id, tag, added_by, added_at)`** — PK `(plan_id, tag)`.
|
|
126
|
+
Indexed on `tag`. Insert with `OR IGNORE` for idempotency.
|
|
127
|
+
- **`task_tags(task_id, tag, added_by, added_at)`** — PK `(task_id, tag)`.
|
|
128
|
+
Indexed on `tag`. Same idempotent insert pattern.
|
|
129
|
+
|
|
130
|
+
### View
|
|
131
|
+
|
|
132
|
+
- **`plan_progress`** — computed from `plans` LEFT JOIN `plan_tasks` (excluding
|
|
133
|
+
archived tasks, `src/db/schema.ts:413-431`). Columns: `plan_id`, `slug`, `title`,
|
|
134
|
+
`status`, `total_tasks`, `done`, `failed`, `running`, `pending`, `blocked`,
|
|
135
|
+
`progress_pct` (percentage rounded to integer).
|
|
136
|
+
|
|
137
|
+
### Migrations
|
|
138
|
+
|
|
139
|
+
5 migrations applied automatically by `runMigrations(db)` ordered by version:
|
|
140
|
+
|
|
141
|
+
| Version | Description |
|
|
142
|
+
|---|---|
|
|
143
|
+
| v1 | Initial schema: plans, plan_tasks, sessions, FTS5 (porter), sync triggers |
|
|
144
|
+
| v2 | Discriminated metadata, audit columns, plan_tags/task_tags M:N, plans_fts_v2 (contentless) |
|
|
145
|
+
| v3 | `updated_at` triggers, composite indexes, session FK app-level validation |
|
|
146
|
+
| v4 | Priority/slug validation triggers, `plan_progress` view, FTS5 unicode61 diacritics, Spanish stopwords table, metadata default trigger |
|
|
147
|
+
| v5 | Soft delete (`archived_at` columns), `plans_fts_v2` switched to external content (`content='plans'`), `plan_progress` excludes archived tasks |
|
|
148
|
+
|
|
149
|
+
`SCHEMA_V5_SQL` note: columns are added via `addColumnIfMissing()` in `migrations.ts`
|
|
150
|
+
because SQLite 3.45 lacks `IF NOT EXISTS` for `ALTER TABLE ADD COLUMN` (`src/db/schema.ts:400-403`).
|
|
151
|
+
|
|
152
|
+
## Tools (22)
|
|
153
|
+
|
|
154
|
+
### Plans (8)
|
|
155
|
+
|
|
156
|
+
| Tool | Args | Returns |
|
|
157
|
+
|---|---|---|
|
|
158
|
+
| `plan_create` | `slug`, `title`, `overview`, `approach?`, `priority?`, `complexity?`, `sessionId?`, `metadata?` | `Plan` (JSON) |
|
|
159
|
+
| `plan_get` | `id?` OR `slug?` | `Plan \| null` (JSON) |
|
|
160
|
+
| `plan_list` | `status?`, `sessionId?`, `limit?` | `Plan[]` (JSON) |
|
|
161
|
+
| `plan_search` | `query`, `limit?`, `includeArchived?` | `Plan[]` (JSON, FTS5 ranked) |
|
|
162
|
+
| `plan_approve` | `id` | `Plan \| null` (JSON) |
|
|
163
|
+
| `plan_update_status` | `id`, `status` (enum: `draft`/`approved`/`executing`/`completed`/`failed`/`abandoned`), `dryRun?`, `force?`, `forceReason?` | `{plan, statusChanged, blocked, forced, dryRun, blockers, warnings, archived, archiveError, auditId}` (JSON) |
|
|
164
|
+
| `plan_progress` | `planId?`, `owner?` | Progress rows[] (JSON) |
|
|
165
|
+
| `plan_files_write` | `planId`, `files[]` (array of `{filePath, role}`) | `{planId, inserted, totalRequested}` (JSON) |
|
|
166
|
+
|
|
167
|
+
- `plan_create` generates a UUID v4 internally via `crypto.randomUUID()` (`src/plugin.ts:581`).
|
|
168
|
+
- `plan_update_status` auto-archives when status is `completed`, `failed`, or `abandoned`
|
|
169
|
+
(`src/plugin.ts:688-697`). Archive errors are non-blocking (logged as warning).
|
|
170
|
+
Extended with readiness checks: `dryRun=true` returns blockers/warnings without mutating.
|
|
171
|
+
`force=true` with `forceReason` bypasses blockers (except `status_invalid`), captured to `plan_audit`.
|
|
172
|
+
Triggers auto-checkpoint on phase transition (`src/db/auto-checkpoint.ts`).
|
|
173
|
+
- `plan_progress` queries the `plan_progress_active` view (excludes archived plans). When `owner` is provided,
|
|
174
|
+
JOINs with `plans` and filters via `json_extract(metadata, '$.ownedBy')` (`src/plugin.ts:843`).
|
|
175
|
+
- `plan_files_write` uses `INSERT OR IGNORE` for idempotency. PK is `(plan_id, file_path, role)`.
|
|
176
|
+
Roles: "input", "modified", "output", "reference" (`src/plugin.ts:875`).
|
|
177
|
+
|
|
178
|
+
### Tasks (9)
|
|
179
|
+
|
|
180
|
+
| Tool | Args | Returns |
|
|
181
|
+
|---|---|---|
|
|
182
|
+
| `task_create_batch` | `planId`, `tasks[]` (array of `{description, agent, files?, complexity?, dependencies?, metadata?}`) | `PlanTask[]` (JSON) |
|
|
183
|
+
| `task_list` | `planId`, `status?` | `PlanTask[]` (JSON) |
|
|
184
|
+
| `task_update_status` | `id`, `status` (enum), `result?`, `error?`, `artifacts?`, `metadataPatch?`, `reviewedBy?`, `reviewedVerdict?` | `PlanTask \| null` (JSON) |
|
|
185
|
+
| `task_search` | `query`, `limit?`, `includeArchived?` | `PlanTask[]` (JSON, FTS5 ranked) |
|
|
186
|
+
| `task_next_for_agent` | `agent`, `planId?` | `PlanTask \| null` (JSON) |
|
|
187
|
+
| `task_peek_for_agent` | `agent`, `planId?`, `limit?` | `PlanTask[]` (JSON) |
|
|
188
|
+
| `task_add_artifact` | `taskId`, `artifact`, `role?` | `{task, added}` (JSON) |
|
|
189
|
+
| `task_review` | `taskId`, `reviewedBy`, `verdict` | `{task}` (JSON) |
|
|
190
|
+
| `task_dependency_resolver` | `taskId?` OR `planId?` + `orderIndex?` | `{canStart, pendingDeps, runningDeps, failedDeps, blockedDeps, doneDeps, missingDeps, dependencies}` (JSON) |
|
|
191
|
+
|
|
192
|
+
- `task_create_batch` is transactional — all tasks insert or none (`src/db/tasks.ts:24-77`).
|
|
193
|
+
Status defaults to `pending`. Each task gets a UUID and sequential `order_index`.
|
|
194
|
+
- `task_update_status` truncates `result` and `error` to 16KB max (`"…[truncated]"` suffix,
|
|
195
|
+
`src/db/tasks.ts:109-121`). Sets `started_at` on `running`, `completed_at` on `done`/`failed`.
|
|
196
|
+
Also accepts `artifacts` (replaces array, truncated if >16KB), `metadataPatch` (deep merged into existing
|
|
197
|
+
metadata), `reviewedBy` (sets `reviewed_by` column), and `reviewedVerdict` (stored in `metadata` JSON)
|
|
198
|
+
(`src/db/tasks.ts:316-428`). All new fields are optional — retrocompatible with existing callers.
|
|
199
|
+
- `task_next_for_agent` returns the first `pending` task ordered by `order_index`
|
|
200
|
+
for the given agent, optionally scoped to a plan.
|
|
201
|
+
- `task_peek_for_agent` is read-only — unlike `task_next_for_agent`, it does NOT claim the task (no status
|
|
202
|
+
change). Returns pending tasks ordered by `order_index`, excludes archived (`src/plugin.ts:1030`).
|
|
203
|
+
- `task_add_artifact` appends to the existing `artifacts` array (dedup — returns `added: false` if already
|
|
204
|
+
present). If `role` is provided, also inserts into `plan_files` (`src/plugin.ts:1056`).
|
|
205
|
+
- `task_review` only works on tasks with `status='done'`. Sets `reviewed_by` column and stores `reviewedVerdict`
|
|
206
|
+
in `metadata` JSON (`src/plugin.ts:1089`).
|
|
207
|
+
- `task_dependency_resolver` resolves a task's dependencies by classifying each dep ID by its current status.
|
|
208
|
+
Returns `canStart` (true iff all deps are `done`) plus categorized arrays. Accepts `taskId` directly,
|
|
209
|
+
or `planId` + `orderIndex` to look up the task (`src/db/tasks.ts:449-510`).
|
|
210
|
+
|
|
211
|
+
### Sessions (3)
|
|
212
|
+
|
|
213
|
+
| Tool | Args | Returns |
|
|
214
|
+
|---|---|---|
|
|
215
|
+
| `session_start` | `id`, `goal`, `planId?`, `metadata?` | `Session` (JSON) |
|
|
216
|
+
| `session_checkpoint` | `id`, `state` (record), `keyDecisions?` | `Session \| null` (JSON) |
|
|
217
|
+
| `session_end` | `id` | `Session \| null` (JSON) |
|
|
218
|
+
|
|
219
|
+
- `session_start` sets `started_at` and `last_checkpoint` to now (`src/db/sessions.ts:24-38`).
|
|
220
|
+
- `session_checkpoint` updates `last_checkpoint`, `state`, and appends `key_decisions`
|
|
221
|
+
using `COALESCE(?, key_decisions)` to preserve existing decisions (`src/db/sessions.ts:81-85`).
|
|
222
|
+
- `session_end` sets `ended_at` only if not already set (`WHERE ended_at IS NULL`,
|
|
223
|
+
`src/db/sessions.ts:110`). Returns `null` if already ended.
|
|
224
|
+
|
|
225
|
+
### Ops (2)
|
|
226
|
+
|
|
227
|
+
| Tool | Args | Returns |
|
|
228
|
+
|---|---|---|
|
|
229
|
+
| `incident_create` | `title`, `severity` (enum: sev1-4), `summary?`, `triggeredByDeploymentId?`, `metadata?` | `Incident` (JSON) |
|
|
230
|
+
| `rollback_record` | `deploymentId`, `plan`, `incidentId?`, `status?` (enum), `newDeploymentId?`, `metadata?` | `RollbackExecution` (JSON) |
|
|
231
|
+
|
|
232
|
+
- `incident_create` validates severity enum (sev1-4) and FK on `triggeredByDeploymentId` if provided.
|
|
233
|
+
Sets `metadata.created_by` from `ctx.agent ?? "unknown"` (`src/plugin.ts:1121`).
|
|
234
|
+
- `rollback_record` requires `deploymentId` (FK validated), optional `incidentId`/`newDeploymentId` (FK validated).
|
|
235
|
+
Sets `metadata.executed_by_agent` from `ctx.agent ?? "unknown"` (`src/plugin.ts:1144`).
|
|
236
|
+
|
|
237
|
+
## Lifecycle
|
|
238
|
+
|
|
239
|
+
### Foreman 10-step lifecycle (`agents/foreman.md`)
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
User → foreman
|
|
243
|
+
| 1. Receive user request (clarify if ambiguous)
|
|
244
|
+
| 2. plan_create("draft") — UUID, slug, priority, overview, approach
|
|
245
|
+
| → auto-creates a session row in `sessions` (ensureSession) for FK integrity,
|
|
246
|
+
| keyed by ctx.sessionID with `goal = "Plan: <title>"`. If `session_start` is needed (step 5) for explicit dispatch tracking, use a different session id — calling it with the same `ctx.sessionID` would collide with the auto-row (PK violation).
|
|
247
|
+
| ensureSession is idempotent.
|
|
248
|
+
| 3. plan_approve — seal approved_at, transition to "approved"
|
|
249
|
+
| 4. task_create_batch — one task per agent with dependencies
|
|
250
|
+
| 5. session_start — link to planId
|
|
251
|
+
| 6. Dispatch loop:
|
|
252
|
+
| task_next_for_agent → agent executes → task_update_status
|
|
253
|
+
| 7. session_checkpoint — at each milestone (min 1 per phase)
|
|
254
|
+
| 8. Reconcile — verify all tasks done/failed before closing
|
|
255
|
+
| 9. plan_update_status("completed") — triggers auto-archive
|
|
256
|
+
| 10. session_end — set ended_at
|
|
257
|
+
↓
|
|
258
|
+
Done
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Auto-archive
|
|
262
|
+
|
|
263
|
+
- **Trigger**: `plan_update_status` when `status` ∈ `{completed, failed, abandoned}`
|
|
264
|
+
(`src/plugin.ts:688-694`).
|
|
265
|
+
- **Output**: Markdown file at `<project>/.ndomo/archives/plans/<slug>-YYYY-MM-DD.md` with:
|
|
266
|
+
- Title, slug, status, priority, complexity, plan ID
|
|
267
|
+
- Overview and approach sections
|
|
268
|
+
- Task list with checkboxes (`[x]` for done), agent, complexity, status, result, error
|
|
269
|
+
- Session list with timestamps, goal, and key decisions
|
|
270
|
+
- Metadata as JSON block
|
|
271
|
+
- **Collision handling**: If filename exists, appends HHMMSS suffix (`src/db/plan-archive.ts:180-190`).
|
|
272
|
+
- **Transactional**: DB update wrapped in `db.transaction()`. Markdown file deleted on
|
|
273
|
+
DB failure (rollback, `src/db/plan-archive.ts:222-229`).
|
|
274
|
+
- **Non-blocking**: Archive errors are caught and logged as warnings; status update
|
|
275
|
+
succeeds regardless (`src/plugin.ts:692-697`).
|
|
276
|
+
- **DB effect**: Sets `archived_at` on plan, all its tasks, and linked sessions via
|
|
277
|
+
cascade UPDATE (`src/db/plan-archive.ts:196-219`).
|
|
278
|
+
- **Filters**: Archived records are excluded by default. Pass `includeArchived: true`
|
|
279
|
+
to `plan_search`, `task_search`, `task_list`, `task_next_for_agent` to retrieve them.
|
|
280
|
+
`plan_list` does not currently expose `includeArchived` in the tool schema.
|
|
281
|
+
|
|
282
|
+
## Dual plan system
|
|
283
|
+
|
|
284
|
+
| System | Storage | Purpose |
|
|
285
|
+
|---|---|---|
|
|
286
|
+
| ndomo plugin DB | `<project>/.ndomo/state.db` (SQLite) | Structured plans with FTS5 search, audit trail, tag taxonomy, cascade archive |
|
|
287
|
+
| ndomo plan archive | `<project>/.ndomo/archives/plans/<slug>-YYYY-MM-DD.md` (markdown) | Auto-generated snapshot on plan completion/failure; not configurable via `mem.storagePath` |
|
|
288
|
+
| opencode-planning-toolkit | `docs/plans/<slug>.md` (markdown) | Lightweight plan notes, git-committable, human-readable |
|
|
289
|
+
| opencode-mem | `~/.ndomo/mem/` (USearch vector DB) | Semantic memory for cross-session recall only — path controlled by `mem.storagePath`, does NOT affect plan archive |
|
|
290
|
+
|
|
291
|
+
These are complementary. Use ndomo DB for orchestration (plans → tasks → sessions);
|
|
292
|
+
use the plan archive for auto-generated markdown snapshots per project;
|
|
293
|
+
use planning-toolkit for plan-as-document; use opencode-mem for semantic recall.
|
|
294
|
+
|
|
295
|
+
## Inspection
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
# Count records by status
|
|
299
|
+
sqlite3 .ndomo/state.db "SELECT status, COUNT(*) FROM plans GROUP BY status"
|
|
300
|
+
sqlite3 .ndomo/state.db "SELECT agent, status, COUNT(*) FROM plan_tasks GROUP BY agent, status"
|
|
301
|
+
|
|
302
|
+
# Find plans by tag
|
|
303
|
+
sqlite3 .ndomo/state.db "SELECT p.title, p.status FROM plans p JOIN plan_tags t ON t.plan_id = p.id WHERE t.tag = 'refactor'"
|
|
304
|
+
|
|
305
|
+
# FTS5 search
|
|
306
|
+
sqlite3 .ndomo/state.db "SELECT title FROM plans_fts_v2 WHERE plans_fts_v2 MATCH 'auth'"
|
|
307
|
+
|
|
308
|
+
# View progress
|
|
309
|
+
sqlite3 .ndomo/state.db "SELECT slug, total_tasks, done, progress_pct FROM plan_progress ORDER BY progress_pct DESC"
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Backup & migration
|
|
313
|
+
|
|
314
|
+
The DB is project-local at `<project>/.ndomo/state.db`. To backup:
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
cp .ndomo/state.db ~/.ndomo/backups/state-$(date +%Y%m%d).db
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Archived plans live at `<project>/.ndomo/archives/plans/<slug>-YYYY-MM-DD.md` — these are
|
|
321
|
+
git-friendly and survive DB deletion.
|
|
322
|
+
|
|
323
|
+
Migrations are applied automatically by `runMigrations(db)` on plugin startup.
|
|
324
|
+
The `schema_version` table tracks applied versions. Manual migration is not
|
|
325
|
+
required.
|
|
326
|
+
|
|
327
|
+
## Schema v13 — ops tables
|
|
328
|
+
|
|
329
|
+
Migration v13 adds 5 tables for operational tracking (warden scope). All use `CREATE TABLE IF NOT EXISTS`
|
|
330
|
+
(idempotent — no `addColumnIfMissing` needed). Registered in `MIGRATIONS` array (`src/db/schema.ts:820-823`).
|
|
331
|
+
|
|
332
|
+
### Tables
|
|
333
|
+
|
|
334
|
+
| Table | Purpose | Key columns |
|
|
335
|
+
|---|---|---|
|
|
336
|
+
| `environments` | Named deployment targets (prod, staging, dev) | id, name (UNIQUE), slug (UNIQUE), description, metadata, archived_at |
|
|
337
|
+
| `releases` | Versioned artifacts deployable to environments | id, version, title, notes, metadata, archived_at |
|
|
338
|
+
| `deployments` | A release deployed to an environment | id, release_id (FK), environment_id (FK), status (CHECK: planned/in_progress/succeeded/failed/rolled_back), deployed_at |
|
|
339
|
+
| `incidents` | Operational events, optionally linked to a deployment | id, title, severity (CHECK: sev1-4), status (CHECK: open/triaging/mitigated/resolved/postmortem), summary, triggered_by_deployment_id (FK nullable) |
|
|
340
|
+
| `rollback_executions` | Record of a rollback action | id, deployment_id (FK required), incident_id (FK nullable), new_deployment_id (FK nullable), status (CHECK: planned/approved/dry_run/executing/success/failed/cancelled), plan |
|
|
341
|
+
|
|
342
|
+
### FK graph
|
|
343
|
+
|
|
344
|
+
```
|
|
345
|
+
environments ←─── deployments ───→ releases
|
|
346
|
+
↑
|
|
347
|
+
│ triggered_by_deployment_id (nullable)
|
|
348
|
+
incidents
|
|
349
|
+
↑
|
|
350
|
+
│ incident_id (nullable)
|
|
351
|
+
rollback_executions
|
|
352
|
+
│
|
|
353
|
+
├── deployment_id (required) ──→ deployments
|
|
354
|
+
└── new_deployment_id (nullable) ──→ deployments
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Migration notes
|
|
358
|
+
|
|
359
|
+
- **Idempotent**: all 5 tables use `CREATE TABLE IF NOT EXISTS`. Re-running v13 is a no-op.
|
|
360
|
+
- **No special-casing**: the generic `runMigrations(db)` runner handles v13 without addColumnIfMissing.
|
|
361
|
+
- **Rollback strategy**: tables are additive (no ALTER TABLE on existing tables). To remove:
|
|
362
|
+
`DROP TABLE` in FK-safe order: `rollback_executions` → `incidents` → `deployments` → `releases` → `environments`.
|
|
363
|
+
Then decrement `schema_version` to 12.
|
|
364
|
+
- **Indices**: all FK columns + status/severity/created_at have indices for query performance.
|