21 KiB
21 KiB
Repository Guidelines
Project Overview
- identity:
@jamminrebel/pom-omp2.0.0, MIT, ESM — POM 2 "Produce Magnum Opus", an Oh My Pi (OMP) extension. - purpose: turn OMP's native models, tools, task agents, IRC, todo, sessions, approvals, compaction and TUI into an evidence-gated production operating system for long-form creative work (README.md:3).
- governs, never replaces: OMP performs execution; POM adds stage contracts, canonical artifacts, prompt provenance, deterministic validation, Git checkpoints, and an Obsidian/Quartz-compatible vault (README.md:5, POM.yml:6-9, docs/ARCHITECTURE.md:3-27).
- ships: 9 stages (0..8), 7
pom_*tools, 14 task agents, 13 prompt fragments, 3 rules, 2 themes, native task+IRC Hive planning, optional Swarm DAGs, verified ZIP delivery (README.md:9-20). - operator loop:
/pom new "Title"->/pom run next->/pom hive stage->/pom evidence->/pom check stage-> model callspom_stage action=passonly after a PASS report ->/pom export final(README.md:44-56)./pomopens the command center;Alt+Pis the shortcut. - this file is the repository contributor guide. Generated POM projects get their own
AGENTS.mdwritten bybootstrapProject(src/persistence.ts:241-307) — different file, different audience.
Architecture & Data Flow
- flow:
/pomcommand -> parser -> stage machine -> persistence + git + router -> prompt-stack injection -> OMP model turn ->pom_*tools -> validators -> exporter. - entry point: default export
pomExtension(pi: ExtensionAPI)insrc/index.ts; sets labelPOM · Produce Magnum Opus, builds the runtime, then registers in this order:registerPomTools,registerPomRenderers,registerPomEvents,registerPomCommand(src/index.ts:13-49). Keep registration centralized there. - runtime boundary:
src/runtime.tsPomRuntime=get,set,restore,getConfig,refreshConfig,telemetry.setclones state, stampsupdatedAt, appends a session branch entry of typepom-state, writes00_admin/project_state.json, and syncs generated knowledge files whenstate.initialized(src/index.ts:25-31). Never persist state around it.restoreprecedence: session branch viarestoreLatest-><cwd>/00_admin/project_state.json-> fresh uninitialized state (src/index.ts:33-42).
- command layer:
src/command.tsregisterspomplus shortcutalt+pand owns all verbs (new,run,hive,swarm,evidence,check,vault,export,status,prompt,tools,theme,settings,doctor,help).src/parser.tstokenizes quotes/escapes, defaults the verb todashboard, and parses--flag[=value]into a Map. - stage run:
runStage=startStage(gotoStage(...))->runtime.set->enterStageBranch->routeStage->updateChrome->pi.sendUserMessage(await renderStagePrompt(...), { deliverAs: "followUp" })(src/command.ts:94-105). - routing:
src/router.tsapplies the stage tool profile whenautoToolProfiles, resolvesspec.modelRoleviactx.models.resolve, callspi.setModel, and sets thinkingxhighfor every stage except stage 7 (high). - domain:
src/domain.tsholdsPOM_VERSION/POM_SCHEMA_VERSION(both "2.0.0"),STAGES: readonly StageSpec[],ArtifactRecord,EvidenceRecord,StageBlocker,StageRunState,HiveTask,HiveMission,PomState,PomConfig,DEFAULT_CONFIG.- stages: 0 init, 1 genre, 2 voice, 3 store, 4 bible, 5 outline, 6 chapters, 7 draft, 8 delivery. Each
StageSpecownsid,slug,name,icon,toolProfile,modelRole,agents,artifacts,acceptance,todos.
- stages: 0 init, 1 genre, 2 voice, 3 store, 4 bible, 5 outline, 6 chapters, 7 draft, 8 delivery. Each
- state machine:
src/state.ts, clone-then-mutate.gotoStagerejects incomplete prerequisites;startStagerejects complete stages and unresolved blockers;passStagerequires an active run, a validation report path, zero unresolved blockers, and evidence for every acceptance criterion (src/state.ts:97-188).recordEvidencechecks the criterion belongs to the active stage, demands a non-empty summary plus >=1 path, de-duplicates normalized paths, replaces prior evidence for that criterion (src/state.ts:144-168).- canonical state path:
<projectRoot>/00_admin/project_state.jsonviastatePath.
- persistence:
src/persistence.tsserializes writes per absolute path (writeQueues), writes a temp file thenrename, and appends a trailing newline to JSON.- manifest
00_admin/artifact_manifest.json: entries need safe unique relative paths, stage 0..8, semver version, valid status, SHA-256, positive bytes, parseableupdatedAt, valid rights status. registerArtifact:secureExistingPath-> reject empty file ->relativeProjectPath-> SHA-256 -> manifest save ->artifact.registeredin00_admin/artifact_events.jsonl-> knowledge sync (src/persistence.ts:123-163).bootstrapProjectcreates00_admin,01_planning,02_story_bible,03_manuscript/chapters,04_images/{references,generated},05_research,06_ledgers,07_exports,.omp/prompts,content, and refuses a non-empty unrecognized directory that has no00_admin/project_state.json(src/persistence.ts:216-239).
- manifest
- events:
src/events.ts.resources_discoveradvertises bundled../skills,../prompts,../themesviafileURLToPath(new URL(...)); it does not advertiseagents/orrules/.before_agent_startinjects the composed prompt stack intoevent.systemPromptand returns a hiddenpom:eventmessage.- native
task/ircare observed only:tool_call/tool_resultupdate Hive mission status plus telemetry and append durablenative.task.started,native.task.finished,native.irc.send,native.irc.resultledger events.
- prompts:
src/prompts.tsloads bundled../promptsplus project.omp/prompts; id = markdown basename; project fragments override bundled by id; every fragment is SHA-256 stamped in an HTML comment (id/source/hash); a stack is immutable law ->personality-${state.mode}-> requested ids, and each use is logged to the prompt ledger. - delegation:
src/studio.tsbuildsHiveMissionidss${spec.id}-${randomUUID().slice(0,8)}, caps agents atmaxStudioAgents, and converts a mission into one native task batch whose shared context tells agents to coordinate over native IRC and never pass the stage.src/swarm.tsoptionally writes00_admin/swarms/<missionId>.yaml(specialists plus anintegrator) throughsecureFuturePath. - validation:
src/validators.tsvalidatePom(state, scope, opts); scopesquick,stage,canon,continuity,knowledge,files,delivery,all; report schema "1.0.0";passedis true only when no check has statusfail; reports land in00_admin/validation/stage-<n>-<scope>-<stamp>.jsonwhen initialized. - delivery:
src/exporter.tswrites00_admin/SHA256SUMS.txt, a delivery report under07_exports, then07_exports/<projectSlug>-<kind>.zip, verifies it and writes<base>.verification.json.src/zip.ts(yazl create, yauzl read,crc-32) rejects encryption, compression methods other than 0/8, duplicate members, unsafe names, empty archives, size drift and CRC mismatch, and returns the archive SHA-256. - terminal:
src/ui.tswrites statusespom-stage,pom-progress,pom-gate,pom-hiveand widgetpom-hud;src/visual.tsrenders the HUD with width-safe truncation and caches unchanged frames;src/renderers.tsrenders custom message typespom:event,pom:validation,pom:hive,pom:milestoneand adds a thinking lane when enabled and view is not minimal/compact. - git:
src/git.tsshellsexecFile("git", ["-C", root, ...]), initializes when needed, uses branchespom/stage-<id>-<slug>, and checkpoints withgit add -A+git commitunlessgitModedisables it.
Key Directories
- src/: extension source, 25 modules, no build step (OMP loads TypeScript directly).
- tests/: 8
*.test.tsfiles onnode:test, importing production code. - scripts/:
verify.mjs(structural gates),release-manifest.mjs(RELEASE.json generate/check),smoke.ts(runtime smoke),install.sh/install.ps1. - agents/: 14
pom-*.mdspecialist task-agent definitions. - prompts/: 13 prompt fragments; ids are basenames;
personality-*.mdmap toPomMode. - rules/: 3 scoped production rules (
pom-artifact-integrity,pom-continuity,pom-rights). - skills/pom/:
SKILL.mdplusreferences/(core-law.jml,workflow.md,tool-routing.md,todo-blueprints.md,artifacts.md,agent-studios.md,commands.md,qa.md,ui.md). - themes/:
pom-nocturne.json(dark),pom-parchment.json(light). - config/: shipped templates —
config.yml(OMP host settings),pom.json(POM defaults),APPEND_SYSTEM.md,mcp.json.example. - docs/:
ARCHITECTURE.md,SETTINGS.md,TOOL_MATRIX.md,INVENTORY.md,AUDIT.md,DESIGN_REVIEW.md,OFFICIAL_SOURCES.md,POM_ARCHITECTURE.mmd.
Development Commands
- setup:
npm install - typecheck:
npm run check->tsc --noEmit(tsconfig includessrc/**/*.tsonly; tests are not typechecked) - tests:
npm test->node --import tsx --test tests/*.test.ts- one file:
node --import tsx --test tests/state.test.ts - one case:
node --import tsx --test --test-name-pattern="<regex>" tests/state.test.ts
- one file:
- runtime smoke:
npm run smoke->node --import tsx scripts/smoke.ts - structural gates:
node scripts/verify.mjs - release manifest:
npm run release:manifest(write),npm run release:check(fail if stale) - full gate:
npm run verify= check -> test -> smoke -> scripts/verify.mjs -> release:check ->npm pack --dry-run - host install:
npm run link(omp plugin link .), then restart OMP or/reload-plugins, then/pom theme install - host check:
npm run doctor(omp plugin doctor; needs Bun + OMP installed)
Code Conventions & Common Patterns
- imports:
- relative source imports are extensionless:
./state,./domain,./tool-profiles— never.ts/.js, despiteallowImportingTsExtensions: true. - Node builtins use the
node:prefix; OMP SDK types come in asimport type { ExtensionAPI, ExtensionContext } from "@oh-my-pi/pi-coding-agent".
- relative source imports are extensionless:
- errors: throw
Errorfor precondition, schema, config, manifest and path violations (assertState,loadPomConfig,secureExistingPath); represent observable tool failures asisError: trueresults, not throws. - tools: defined in
src/tools.ts; ids are exactlypom_state,pom_stage,pom_artifact,pom_validate,pom_prompt,pom_hive,pom_export.- schemas use
const { z } = pi.zodwith inlinez.object/z.enum; one targeted@ts-expect-errorcovers OMP 16.4.x + Zod v4 instantiation depth (src/tools.ts:58-61) — keep it narrow. - every result goes through
textResult(text, details?, isError = false)->{ content: [{ type: "text", text }], details, isError }. - mutators declare
approval: "write";pom_validateandpom_promptdeclareapproval: "read". - every execute handler returns
textResult("Cancelled", undefined, true)whensignal?.aborted.
- schemas use
- state: clone with
structuredClonebefore nested mutation, then persist throughruntime.set. - async:
async/awaiteverywhere for FS, OMP hooks, tools, config and validation; no callback style. - naming: kebab-case multiword filenames (
tool-profiles.ts); camelCase functions, PascalCase types; POM-owned identifiers keep thepom/pom_/pom-prefix per surface (tool idspom_*, statusespom-*, message typespom:*, agentspom-*). - tool profiles:
src/tool-profiles.tsappends POM tools to host tools for non-autoprofiles, always keepsread, and stores the baseline in aWeakMapkeyed bypi— useresetToolBaselineForTests()rather than assuming a fresh baseline. - config:
src/config.tsmerges built-inDEFAULT_CONFIG->~/.omp/agent/pom.json-><project>/.omp/pom.json, validates booleans/enums/bounded integers and throwsInvalid POM setting ...; writes go temp-file-then-rename.- keys and defaults:
autoToolProfilestrue,autoModelRoutingtrue,dashboardWidgettrue,stopGuardtrue,defaultMode"autopilot",defaultView"cinematic",defaultMotion"subtle",defaultToolProfile"auto",maxStudioAgents6,projectRootMode"child",destructiveProjectCommands"block",gitMode"branch-per-stage",hudPlacement"aboveEditor",showThinkingLanetrue (src/domain.ts:471-486, docs/SETTINGS.md:31-46). - OMP host settings belong in
<project>/.omp/config.yml; the shipped template isconfig/config.ymlandbootstrapProjectwrites the same values (themepom-nocturne/pom-parchment,task.maxConcurrency: 8,compaction.strategy: snapcompact,defaultThinkingLevel: high).
- keys and defaults:
- asset shapes:
- agents: frontmatter
name: pom-<kebab>, non-emptydescription,tools:list that includesyield, plusmodel,thinkingLevel,read-summarize; enforced byscripts/verify.mjs:58-64. - rules: frontmatter
descriptionplusglobsarray. - skill:
skills/pom/SKILL.mdfrontmattername: pom,description,alwaysApply: false. - prompts: frontmatter optional — personality fragments carry
description, operational fragments start with prose; the loader accepts any.md. - themes: keep
$schema,name(must equal filename stem),vars,colors,export;/pom theme installcopiesthemes/*.jsonintogetCustomThemesDir()from@oh-my-pi/pi-utils.
- agents: frontmatter
- POM.yml is the human-facing project/release manifest (boundaries, stages, gate, commands, tools, delegation, terminal, knowledge, integrity, resources, release) — not a runtime schema; nothing loads it at runtime.
Important Files
- src/index.ts: extension entry, runtime construction, registration order.
- src/domain.ts: schema versions,
STAGES, artifact/evidence/blocker/hive/state/config types,DEFAULT_CONFIG. - src/state.ts: stage lifecycle invariants, evidence rules, canonical state path.
- src/persistence.ts: workspace layout, atomic writes, manifest/ledger/knowledge persistence, bootstrap.
- src/tools.ts: the 7
pom_*tool contracts, approvals, result shape. - src/events.ts: OMP event surface, resource discovery, prompt injection, native task/IRC observation.
- src/validators.ts: deterministic checks and report contract.
- src/paths.ts:
canonicalRoot,secureExistingPath,secureFuturePath,relativeProjectPath,assertSafeArchivePath. - scripts/verify.mjs: structural release gates (see Testing & QA).
- scripts/release-manifest.mjs: RELEASE.json generation and
--checkstaleness semantics. - package.json: OMP entry
omp.extensions: ["./src/index.ts"], scripts, peer window, ship list. - tsconfig.json:
target ES2022,module ESNext,moduleResolution Bundler,strict,noEmit,skipLibCheck,allowImportingTsExtensions.
Runtime/Tooling Preferences
- package manager: npm, authoritative
package-lock.json(lockfileVersion 3). Do not introduce bun/pnpm/yarn lockfiles. - local scripts run on Node +
tsx+tsc;engines.bun >= 1.3.14describes the OMP host, andnpm run doctoris the only Bun+OMP gate. - no build step and no
dist/: OMP loadssrc/index.tsdirectly. - SDK window:
@oh-my-pi/pi-coding-agent,pi-tui,pi-utilsare peers at>=16.4.6 <17. Do not use APIs that require OMP 17.x. - runtime dependencies are deliberately three:
crc-32,yauzl,yazl(ZIP integrity). Add a dependency only when the host SDK and Node builtins genuinely cannot do the job. .gitignorecoversnode_modules/,*.tgz,*.zip,coverage/,dist/,.DS_Store,*.log.
Testing & QA
- framework: Node's built-in runner,
import test from "node:test"+import assert from "node:assert/strict", flattest("...")calls, nodescribe. - tests import production code directly with extensionless specifiers (
../src/state); never copy implementation into a test. - filesystem tests isolate with
mkdtemp(join(tmpdir(), ...))and clean up infinallyviarm({ recursive: true, force: true }). - test-file names do not map 1:1 to modules:
tests/command.test.tsexercisessrc/parser.ts,tests/events.test.tsexercisessrc/policy.ts. - covered by unit tests: parser, policy, paths, state, domain, persistence, studio, swarm, validators, zip. Not directly covered:
src/tools.ts,src/visual.ts— add tests there when changing behavior. scripts/smoke.tsis the end-to-end guard: bootstrap a temp project withprojectRootMode: "cwd", assert generated.omp/config.ymlandcontent/production-board.mdcontent, then assertvalidatePom(state, "quick", { writeReport: false }).passed === true.scripts/verify.mjsenforces, and will fail a change that breaks any of these:- required files exist, including
src/index.ts,src/events.ts,src/tools.ts,src/visual.ts,skills/pom/SKILL.md,config/APPEND_SYSTEM.md,prompts/stage-run.md, both themes,scripts/smoke.ts. RELEASE.json.version === package.json.version; release inventory stages/customTools/behavioralTests = 9/7/9;pkg.omp.extensionsdeep-equals["./src/index.ts"];pkg.version === "2.0.0"; everypackage.json.filesentry exists.- exactly one
registerCommand("pom"and oneregisterShortcut("alt+p"insrc/command.ts; exactly nineid: 0..8stage ids insrc/domain.ts; exactly sevenname: "pom_*"tools insrc/tools.ts. src/tools.tscontains none ofallowArgs,formatApprovalDetails,concurrency: "exclusive",ExtensionAPI = any;src/omp-shim.d.tsandsrc/node-shim.d.tsmust not exist.- asset counts 14 agents / 13 prompts / 3 rules / 2 themes, agent frontmatter shape, theme names and required color keys (read from the installed
@oh-my-pi/pi-coding-agenttheme schema, sonpm installis a prerequisite), and the nine required directories.
- required files exist, including
- after changing any shipped file (anything in
package.json.filespluspackage.json), runnpm run release:manifest;npm run release:checkcompares rendered bytes and fails with "RELEASE.json is stale". - run
npm run verifybefore packaging or linking. Host-level acceptance staysnpm run doctorplus an interactive OMP session:/pomoverlay, HUD, statuses, cards,/pom theme install, and a smoke project taken through stage 0 validation plus a checkpoint archive.
Governance Invariants
Preserve these when changing runtime behavior (source: the shipped contributor guide, rules/*.md, skills/pom/references/core-law.jml).
- do not duplicate host primitives: task, IRC, todo, sessions, approvals, compaction, memory, model execution, TUI. Observe and route them; never build a parallel system.
- stage completion requires active execution, complete evidence, zero open blockers, and a passing validation report. Never mark a stage complete by direct state mutation.
- truth hierarchy: system + explicit user requirements > canonical project files and
00_admin/project_state.json> manifest / evidence / ledgers > live OMP execution > vault projection > memory. The vault is a navigable projection, not a source of truth. - keep canonical state and artifacts under the project root; reject traversal and symlink escape through
src/paths.tshelpers (lexical plus realpath containment) — do not substitute plainjoin/resolvechecks. - never fake tool use, files, citations, images, counts, hashes, checks, ZIP tests, or completion. Partial, missing and blocked states stay disclosed as
PARTIAL/BLOCKED. - artifact claims need real non-empty regular files with measured bytes, SHA-256, category, stage, semver version, status, rights, source and notes recorded in the manifest.
- delivery claims need a fresh archive with safe member names, no duplicates/encryption/unsupported methods, central-directory parsing, decompression, size and CRC-32 checks, an archive hash, and an external verification report.
- continuity: story changes must preserve or explicitly revise canon, timeline, knowledge, relationships, props, injuries, rules, mysteries, setups and payoffs; contradictions require explicit canon selection, dependency mapping, revision logging and revalidation.
- rights: no living-author imitation, fabricated quotations, unauthorized asset redistribution, invented private-identity facts, or unsupported rights claims.
- use OMP renderers and UI hooks (
setWidget,setStatus,setWorkingMessage, message cards) instead of printing raw terminal control sequences. - delegation: one widest safe native task batch per independent wave, each task carrying objective, owned files and acceptance conditions; keep IRC terse with the
CLAIM / QUERY / ANSWER / ALERT / HANDOFF / DONEvocabulary; durable findings go into project files or ledgers, not chat. - tool routing: native tool first —
readfor files/directories/archives/static URLs,globfor bounded discovery,grepfor bounded regex, AST/LSP for symbol work, browser only for authenticated/interactive/JS-only pages,askonly after exhausting sources.
Known Discrepancies
Verified inconsistencies in the current tree — do not "fix" them silently as part of unrelated work, and do not describe them as working.
pom_stageaccepts aninspectaction in its schema with no dedicated branch; it falls through to the sync/refresh path and returns summary state. Decision: keep as summary fallback; if dedicated inspect behavior is needed, add a branch and update schema/tests.resources_discoveradvertises only skills, prompts and themes;agents/andrules/are shipped but not advertised through that event. Decision: agents and rules are packaging-only resources; add them to resources_discover if/when agent-facing discovery is required.docs/INVENTORY.mdclaims "9 behavioral tests across 8 test files"; the tree contains 8 test files with 9 test declarations.scripts/verify.mjsasserts the manifest number (9) without distinguishing file count from declaration count.