254 lines
9.3 KiB
Markdown
254 lines
9.3 KiB
Markdown
|
|
# Manifest Self-Interrogation — Enrichment Prompt
|
|||
|
|
|
|||
|
|
**Purpose:** Populate `capabilities[]`, `requirements[]`, and `critical_deps[]` in
|
|||
|
|
`{project_name}`'s `.ontology/manifest.ncl`. These fields answer the operational
|
|||
|
|
self-knowledge questions that ontology Practice nodes don't: what does the project
|
|||
|
|
do and why, what does it need to run, and what external dependencies carry blast
|
|||
|
|
radius when they break.
|
|||
|
|
|
|||
|
|
**Substitutions required before use:**
|
|||
|
|
- `{project_name}` — kebab-case project identifier
|
|||
|
|
- `{project_dir}` — absolute path to project root
|
|||
|
|
|
|||
|
|
**Requires:** `ontoref` installed globally (`just install-daemon` from the ontoref repo).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Bootstrap — source ontoref env vars
|
|||
|
|
|
|||
|
|
Before running any direct `nickel export` command, source the ontoref env into the current
|
|||
|
|
shell:
|
|||
|
|
|
|||
|
|
```sh
|
|||
|
|
cd {project_dir}
|
|||
|
|
. $(which ontoref) --env-only
|
|||
|
|
# NICKEL_IMPORT_PATH and ONTOREF_ROOT are now available in this shell session
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Context for the agent
|
|||
|
|
|
|||
|
|
You are enriching `.ontology/manifest.ncl` for project `{project_name}`. The three
|
|||
|
|
new arrays are semantically distinct — do not conflate them:
|
|||
|
|
|
|||
|
|
- `capabilities[]` — operational, audience-facing. What the project offers, why it
|
|||
|
|
was built, how it works at implementation level. Cross-references ontology node IDs
|
|||
|
|
(`nodes[]`) and the ADRs that formalize design decisions (`adrs[]`). These are not
|
|||
|
|
architectural invariants — they evolve freely.
|
|||
|
|
- `requirements[]` — prerequisites to start. Classified by `env` (Production /
|
|||
|
|
Development / Both) and `kind` (Tool / Service / EnvVar / Infrastructure). Focus
|
|||
|
|
on `impact` (what breaks if absent) and `provision` (how to satisfy it).
|
|||
|
|
- `critical_deps[]` — runtime load-bearing external dependencies. Not "you need this
|
|||
|
|
to start" but "if this breaks or disappears, these capabilities degrade in these
|
|||
|
|
ways". `failure_impact` is required. Include feature flags or fallback builds in
|
|||
|
|
`mitigation`.
|
|||
|
|
|
|||
|
|
All entries must pass `nickel export` cleanly. Do not add entries you cannot
|
|||
|
|
substantiate by reading the code.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase 1 — Read the project
|
|||
|
|
|
|||
|
|
Before writing anything, understand the project. Read in order:
|
|||
|
|
|
|||
|
|
```sh
|
|||
|
|
cd {project_dir}
|
|||
|
|
|
|||
|
|
# Architecture and purpose
|
|||
|
|
cat README.md
|
|||
|
|
cat .claude/CLAUDE.md 2>/dev/null || true
|
|||
|
|
|
|||
|
|
# Existing ontology — understand Practice nodes already declared
|
|||
|
|
nickel export --import-path "$NICKEL_IMPORT_PATH" .ontology/core.ncl \
|
|||
|
|
| jq '[.nodes[] | {id, name, level, description}]'
|
|||
|
|
|
|||
|
|
# Existing manifest — see what is already declared
|
|||
|
|
nickel export --import-path "$NICKEL_IMPORT_PATH" .ontology/manifest.ncl \
|
|||
|
|
| jq '{description, capabilities: (.capabilities | length), requirements: (.requirements | length), critical_deps: (.critical_deps | length)}'
|
|||
|
|
|
|||
|
|
# Cargo workspace — understand crate boundaries
|
|||
|
|
cat Cargo.toml 2>/dev/null || true
|
|||
|
|
ls crates/ 2>/dev/null || true
|
|||
|
|
|
|||
|
|
# External dependencies with most weight
|
|||
|
|
cargo metadata --format-version 1 2>/dev/null \
|
|||
|
|
| jq '[.packages[] | select(.source == null) | {name, dependencies: [.dependencies[] | .name]}]' \
|
|||
|
|
2>/dev/null | head -60 || true
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Identify:
|
|||
|
|
1. What the project does for each audience (developer, agent, CI, end user)
|
|||
|
|
2. Which Cargo features are optional vs default
|
|||
|
|
3. What external services are consumed (databases, message buses, APIs)
|
|||
|
|
4. What environment variables the project reads at startup
|
|||
|
|
5. Which dependencies are foundational (the project cannot function if they break their contract)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase 2 — Add `description` field
|
|||
|
|
|
|||
|
|
If `.ontology/manifest.ncl` has no `description` field, add it immediately after `repo_kind`:
|
|||
|
|
|
|||
|
|
```nickel
|
|||
|
|
description = "One sentence: what is this project and for whom.",
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Confirm with:
|
|||
|
|
```sh
|
|||
|
|
nickel export --import-path "$NICKEL_IMPORT_PATH" .ontology/manifest.ncl | jq .description
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase 3 — Populate `capabilities[]`
|
|||
|
|
|
|||
|
|
For each major capability the project offers, write one entry. Use the builders:
|
|||
|
|
|
|||
|
|
```nickel
|
|||
|
|
capabilities = [
|
|||
|
|
m.make_capability {
|
|||
|
|
id = "kebab-id",
|
|||
|
|
name = "Short Name",
|
|||
|
|
summary = "One line: what does this capability do?",
|
|||
|
|
rationale = "Why does this exist? What problem does it solve? What was consciously rejected?",
|
|||
|
|
how = "Implementation level: key patterns, entry points, data flows.",
|
|||
|
|
artifacts = [
|
|||
|
|
"crates/foo/src/lib.rs",
|
|||
|
|
"GET /api/endpoint",
|
|||
|
|
"reflection/modes/foo.ncl",
|
|||
|
|
],
|
|||
|
|
adrs = [], # ADR IDs that formalize decisions in this capability
|
|||
|
|
nodes = [], # ontology node IDs from core.ncl that this capability manifests
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Guidelines:**
|
|||
|
|
- Aim for 2–6 capabilities. Do not list every feature — group by audience-facing concern.
|
|||
|
|
- `nodes[]` must match IDs declared in `.ontology/core.ncl`. Verify:
|
|||
|
|
```sh
|
|||
|
|
nickel export --import-path "$NICKEL_IMPORT_PATH" .ontology/core.ncl | jq '[.nodes[].id]'
|
|||
|
|
```
|
|||
|
|
- `adrs[]` must match IDs in `adrs/adr-*.ncl`. Verify:
|
|||
|
|
```sh
|
|||
|
|
ls adrs/adr-*.ncl | sed 's|adrs/||;s|-[^-]*\.ncl||'
|
|||
|
|
```
|
|||
|
|
- `how` and `rationale` can be empty strings (`""`) if there is nothing substantive to say.
|
|||
|
|
Do not pad with generic prose.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase 4 — Populate `requirements[]`
|
|||
|
|
|
|||
|
|
For each prerequisite to run the project (prod or dev), write one entry:
|
|||
|
|
|
|||
|
|
```nickel
|
|||
|
|
requirements = [
|
|||
|
|
m.make_requirement {
|
|||
|
|
id = "kebab-id",
|
|||
|
|
name = "Human Name",
|
|||
|
|
env = 'Both, # 'Production | 'Development | 'Both
|
|||
|
|
kind = 'Tool, # 'Tool | 'Service | 'EnvVar | 'Infrastructure
|
|||
|
|
version = "0.x", # empty string if no constraint
|
|||
|
|
required = true,
|
|||
|
|
impact = "What breaks or degrades if this is absent.",
|
|||
|
|
provision = "How to install, set, or provision this.",
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Decision tree for `env`:**
|
|||
|
|
- Only needed to build/test/lint → `'Development`
|
|||
|
|
- Only needed when the service is deployed → `'Production`
|
|||
|
|
- Needed in both contexts → `'Both`
|
|||
|
|
|
|||
|
|
**Decision tree for `kind`:**
|
|||
|
|
- Binary on PATH (`nu`, `nickel`, `cargo`, `just`) → `'Tool`
|
|||
|
|
- External running service (`postgres`, `redis`, `nats`) → `'Service`
|
|||
|
|
- Environment variable that must be set (`DATABASE_URL`, `API_KEY`) → `'EnvVar`
|
|||
|
|
- Filesystem layout, platform, or network topology → `'Infrastructure`
|
|||
|
|
|
|||
|
|
**What to include:**
|
|||
|
|
- Runtime tools (nushell, nickel, just, docker)
|
|||
|
|
- Feature-gated services (database, message bus) — mark `required = false` if optional
|
|||
|
|
- Required env vars (especially secrets and URLs)
|
|||
|
|
- Repo layout dependencies (sibling checkouts, path dependencies in Cargo.toml)
|
|||
|
|
|
|||
|
|
**What to exclude:**
|
|||
|
|
- Standard Rust toolchain (assumed for all Rust projects)
|
|||
|
|
- OS-level libraries already declared in Cargo dependencies
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase 5 — Populate `critical_deps[]`
|
|||
|
|
|
|||
|
|
List only external dependencies whose failure has a documented blast radius. This is not
|
|||
|
|
a full dependency audit — focus on load-bearing external contracts:
|
|||
|
|
|
|||
|
|
```nickel
|
|||
|
|
critical_deps = [
|
|||
|
|
m.make_critical_dep {
|
|||
|
|
id = "kebab-id",
|
|||
|
|
name = "crate-or-service-name",
|
|||
|
|
ref = "crates.io: foo / github.com/org/repo",
|
|||
|
|
used_for = "Which capabilities or features depend on this.",
|
|||
|
|
failure_impact = "What breaks if this dep disappears or breaks its API contract.",
|
|||
|
|
mitigation = "Feature flags, fallback builds, or alternative paths. Empty if none.",
|
|||
|
|
},
|
|||
|
|
],
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Candidates to consider:**
|
|||
|
|
- HTTP framework (axum, actix-web) — entire API surface goes down
|
|||
|
|
- Serialization crates with unusual API stability guarantees
|
|||
|
|
- `inventory` or other linker-section crates — catalog surfaces go silent
|
|||
|
|
- Database driver — persistence layer failure
|
|||
|
|
- Any proc-macro crate the project defines (breakage cascades to all users)
|
|||
|
|
- External APIs called at runtime without a fallback
|
|||
|
|
|
|||
|
|
**Do not include:**
|
|||
|
|
- `serde` / `tokio` / `tracing` — industry-stable, ubiquitous, low blast-radius
|
|||
|
|
- Dev-only dependencies (test frameworks, criterion, cargo-nextest)
|
|||
|
|
- Transitive dependencies the project has no direct contract with
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase 6 — Validate
|
|||
|
|
|
|||
|
|
```sh
|
|||
|
|
cd {project_dir}
|
|||
|
|
|
|||
|
|
# Must export without errors
|
|||
|
|
nickel export --import-path "$NICKEL_IMPORT_PATH" .ontology/manifest.ncl
|
|||
|
|
|
|||
|
|
# Confirm counts
|
|||
|
|
nickel export --import-path "$NICKEL_IMPORT_PATH" .ontology/manifest.ncl \
|
|||
|
|
| jq '{description, capabilities: (.capabilities | length), requirements: (.requirements | length), critical_deps: (.critical_deps | length)}'
|
|||
|
|
|
|||
|
|
# Confirm nodes[] cross-references are valid
|
|||
|
|
nickel export --import-path "$NICKEL_IMPORT_PATH" .ontology/manifest.ncl \
|
|||
|
|
| jq '[.capabilities[].nodes[]]' > /tmp/cap_nodes.json
|
|||
|
|
nickel export --import-path "$NICKEL_IMPORT_PATH" .ontology/core.ncl \
|
|||
|
|
| jq '[.nodes[].id]' > /tmp/core_ids.json
|
|||
|
|
# All capability node refs must appear in core_ids — check manually if jq diff not available
|
|||
|
|
|
|||
|
|
# Smoke test describe output
|
|||
|
|
ontoref --actor developer describe requirements
|
|||
|
|
ONTOREF_ACTOR=agent ontoref describe capabilities | from json | get capabilities | length
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Checklist
|
|||
|
|
|
|||
|
|
- [ ] `description` field populated (non-empty)
|
|||
|
|
- [ ] At least 1 capability entry with non-empty `summary`
|
|||
|
|
- [ ] `nodes[]` entries verified against `.ontology/core.ncl` node IDs
|
|||
|
|
- [ ] At least 1 requirement per environment context that applies (Production / Development)
|
|||
|
|
- [ ] All `critical_deps` have non-empty `failure_impact`
|
|||
|
|
- [ ] `nickel export` passes cleanly with no contract errors
|
|||
|
|
- [ ] `describe requirements` renders without errors
|
|||
|
|
- [ ] `ONTOREF_ACTOR=agent ontoref describe capabilities | from json | get capabilities | length` > 0
|