@michaelmusyoka/eng-os-kit 1.0.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.
Files changed (33) hide show
  1. package/README.md +104 -0
  2. package/bin/eng-os.mjs +222 -0
  3. package/lib/targets.mjs +49 -0
  4. package/package.json +14 -0
  5. package/rules/engineering-contract.md +51 -0
  6. package/scripts/capture-evidence.sh +38 -0
  7. package/scripts/placeholder-audit.sh +51 -0
  8. package/scripts/validate-registry.mjs +71 -0
  9. package/skills/api-database-contract/SKILL.md +38 -0
  10. package/skills/code-review/SKILL.md +39 -0
  11. package/skills/engineering-contract/SKILL.md +40 -0
  12. package/skills/engineering-contract/references/definition-of-done.md +47 -0
  13. package/skills/implementation-prompt/SKILL.md +38 -0
  14. package/skills/incident-response/SKILL.md +34 -0
  15. package/skills/release-gate/SKILL.md +30 -0
  16. package/skills/repo-inspection/SKILL.md +41 -0
  17. package/skills/security-review/SKILL.md +43 -0
  18. package/skills/security-review/references/prompt-injection.md +18 -0
  19. package/skills/signature-dark-ui/SKILL.md +72 -0
  20. package/skills/signature-dark-ui/references/components.md +449 -0
  21. package/skills/signature-dark-ui/references/layout-and-motion.md +1246 -0
  22. package/skills/test-strategy/SKILL.md +36 -0
  23. package/skills/traceability-audit/SKILL.md +46 -0
  24. package/skills/verification-evidence/SKILL.md +30 -0
  25. package/state/decision-log.md +6 -0
  26. package/state/feature-registry.json +18 -0
  27. package/state/feature-registry.schema.json +29 -0
  28. package/state/known-issues.md +6 -0
  29. package/templates/adr.md +19 -0
  30. package/templates/feature-record.md +40 -0
  31. package/templates/implementation-prompt.md +49 -0
  32. package/templates/incident-report.md +29 -0
  33. package/templates/verification-record.md +45 -0
package/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # eng-os-kit
2
+
3
+ An engineering operating system for AI coding agents, installable with npm. Rules that stay in context, standards that load on demand as Agent Skills, and scripts that actually fail a build.
4
+
5
+ Built for **Kilo Code**, and installs just as well into Claude Code, Roo Code, Cursor, or any agent implementing the Agent Skills standard.
6
+
7
+ ## Install
8
+
9
+ Per project (recommended):
10
+
11
+ ```bash
12
+ npx eng-os-kit init
13
+ ```
14
+
15
+ Every project on this machine:
16
+
17
+ ```bash
18
+ npx eng-os-kit init --global
19
+ ```
20
+
21
+ Other agents:
22
+
23
+ ```bash
24
+ npx eng-os-kit init --agent claude
25
+ npx eng-os-kit init --agent all
26
+ ```
27
+
28
+ Then **reload your editor** — Kilo Code only reliably picks up new `SKILL.md` files on reload.
29
+
30
+ ## What lands in your project
31
+
32
+ ```text
33
+ .kilocode/
34
+ ├── rules/00-engineering-contract.md # ~50 lines, always in context
35
+ ├── skills/ # generic skills, loaded on demand
36
+ ├── skills-architect/ # planning skills, Architect mode only
37
+ └── skills-code/ # code + UI skills, Code mode only
38
+ .agent/
39
+ ├── state/feature-registry.json # machine-validated project state
40
+ ├── state/known-issues.md
41
+ ├── state/decision-log.md
42
+ ├── templates/ # prompt, verification, ADR, incident, feature
43
+ ├── scripts/ # the enforcement layer
44
+ ├── prompts/ plans/ audits/ verification/ reports/
45
+ ```
46
+
47
+ ## Commands
48
+
49
+ | Command | Does |
50
+ |---|---|
51
+ | `npx eng-os-kit init` | install rules, skills and `.agent/` scaffolding |
52
+ | `npx eng-os-kit add security-review test-strategy` | install a subset |
53
+ | `npx eng-os-kit list` | every skill and its trigger description |
54
+ | `npx eng-os-kit check` | run the enforcement scripts (CI-safe, exits non-zero) |
55
+ | `npx eng-os-kit doctor` | what is installed where |
56
+
57
+ Flags: `--agent kilocode|claude|roo|cursor|codex|all`, `--global`, `--skills a,b`, `--link` (symlink so `npm update` propagates), `--force`, `--cwd <path>`.
58
+
59
+ ## Skills
60
+
61
+ | Skill | Mode | Triggers on |
62
+ |---|---|---|
63
+ | `engineering-contract` | all | starting non-trivial work, "what's the process" |
64
+ | `repo-inspection` | architect | unfamiliar codebase, before any edit |
65
+ | `implementation-prompt` | architect | auth/money/migrations/integrations, >3 files |
66
+ | `api-database-contract` | all | any endpoint, schema, migration, idempotency |
67
+ | `security-review` | all | auth, permissions, uploads, payments, webhooks |
68
+ | `test-strategy` | all | writing tests, "is this tested", bug found |
69
+ | `traceability-audit` | all | "is this done", before release |
70
+ | `verification-evidence` | all | before claiming anything passed |
71
+ | `release-gate` | all | before any production deploy |
72
+ | `code-review` | code | reviewing a diff, after generating code |
73
+ | `incident-response` | all | production broken, writing a postmortem |
74
+ | `signature-dark-ui` | code | any UI work |
75
+
76
+ ## The enforcement layer
77
+
78
+ Documentation that nothing checks is decoration. Three scripts do the checking:
79
+
80
+ - **`placeholder-audit.sh`** — fails on committed secrets, `TODO`/`FIXME`/`placeholder`/`not implemented`, mocks in production paths; warns on dead `href="#"` links and debug output. Tests, docs and `.agent/` are excluded.
81
+ - **`validate-registry.mjs`** — validates `feature-registry.json` and enforces the rule that matters: a feature cannot be `VERIFIED` or `PRODUCTION_READY` with an empty `evidence` array, or with evidence paths that do not exist.
82
+ - **`capture-evidence.sh`** — runs a command and writes command + exit code + commit SHA + output to `.agent/verification/<feature-id>/`, so evidence is a file rather than a claim.
83
+
84
+ Copy `.github/workflows/eng-os.yml` into your project and make the deploy job `needs: eng-os`. A pipeline that deploys on push without a passing gate makes every gate unreachable.
85
+
86
+ ## Design
87
+
88
+ - **Always in context**: one ~50-line rules file. Precedence, six hard rules, statuses, report format.
89
+ - **On demand**: everything else as a skill. The agent sees only name + description (~100 tokens each) until a task matches.
90
+ - **Machine-checked**: the claims that agents get wrong — "tests pass", "it's complete" — are validated by scripts, not trust.
91
+
92
+ ## Customising
93
+
94
+ Fork it. Edit `rules/engineering-contract.md` and the `skills/` folders, bump the version, then `npm publish` under your own scope, or install straight from git:
95
+
96
+ ```bash
97
+ npx github:<you>/eng-os-kit init
98
+ ```
99
+
100
+ Use `--link` during authoring so edits in the package show up in your project immediately.
101
+
102
+ ## License
103
+
104
+ MIT.
package/bin/eng-os.mjs ADDED
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import os from "node:os";
5
+ import { fileURLToPath } from "node:url";
6
+ import { spawnSync } from "node:child_process";
7
+ import { TARGETS, DEFAULT_TARGET, MODE_SUFFIX_SUPPORT } from "../lib/targets.mjs";
8
+
9
+ const PKG_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
10
+ const pkg = JSON.parse(fs.readFileSync(path.join(PKG_ROOT, "package.json"), "utf8"));
11
+
12
+ const argv = process.argv.slice(2);
13
+ const cmd = argv.find((a) => !a.startsWith("-")) || "help";
14
+ const flag = (name) => argv.includes(`--${name}`);
15
+ const opt = (name, fallback) => {
16
+ const i = argv.findIndex((a) => a === `--${name}` || a.startsWith(`--${name}=`));
17
+ if (i === -1) return fallback;
18
+ const a = argv[i];
19
+ return a.includes("=") ? a.slice(a.indexOf("=") + 1) : argv[i + 1] ?? fallback;
20
+ };
21
+ const positionals = argv.filter((a) => !a.startsWith("-")).slice(1);
22
+
23
+ const c = { r: "\x1b[31m", g: "\x1b[32m", y: "\x1b[33m", d: "\x1b[2m", b: "\x1b[1m", x: "\x1b[0m" };
24
+ process.stdout.on("error", (e) => { if (e.code === "EPIPE") process.exit(0); });
25
+ const say = (m) => process.stdout.write(m + "\n");
26
+ const ok = (m) => say(`${c.g}✓${c.x} ${m}`);
27
+ const warn = (m) => say(`${c.y}!${c.x} ${m}`);
28
+ const die = (m) => { say(`${c.r}✗${c.x} ${m}`); process.exit(1); };
29
+
30
+ const SKILLS_DIR = path.join(PKG_ROOT, "skills");
31
+ const allSkills = () =>
32
+ fs.readdirSync(SKILLS_DIR, { withFileTypes: true })
33
+ .filter((d) => d.isDirectory() && fs.existsSync(path.join(SKILLS_DIR, d.name, "SKILL.md")))
34
+ .map((d) => d.name)
35
+ .sort();
36
+
37
+ function frontmatter(skill) {
38
+ const body = fs.readFileSync(path.join(SKILLS_DIR, skill, "SKILL.md"), "utf8");
39
+ const m = body.match(/^---\n([\s\S]*?)\n---/);
40
+ const out = {};
41
+ if (m) for (const line of m[1].split("\n")) {
42
+ const i = line.indexOf(":");
43
+ if (i > 0) out[line.slice(0, i).trim()] = line.slice(i + 1).trim();
44
+ }
45
+ return out;
46
+ }
47
+
48
+ function copyDir(from, to, { link = false, force = false }) {
49
+ fs.mkdirSync(path.dirname(to), { recursive: true });
50
+ if (fs.existsSync(to)) {
51
+ if (!force) return "skipped";
52
+ fs.rmSync(to, { recursive: true, force: true });
53
+ }
54
+ if (link) { fs.symlinkSync(from, to, "dir"); return "linked"; }
55
+ fs.cpSync(from, to, { recursive: true });
56
+ return "installed";
57
+ }
58
+
59
+ function copyFile(from, to, { force = false }) {
60
+ fs.mkdirSync(path.dirname(to), { recursive: true });
61
+ if (fs.existsSync(to) && !force) return "skipped";
62
+ fs.copyFileSync(from, to);
63
+ return fs.existsSync(to) ? "installed" : "failed";
64
+ }
65
+
66
+ function resolveTarget(name) {
67
+ const t = TARGETS[name];
68
+ if (!t) die(`Unknown --agent "${name}". Choose one of: ${Object.keys(TARGETS).join(", ")}`);
69
+ return t;
70
+ }
71
+
72
+ function base() {
73
+ return flag("global") ? os.homedir() : path.resolve(opt("cwd", process.cwd()));
74
+ }
75
+
76
+ function selected() {
77
+ const req = opt("skills", positionals.length ? positionals.join(",") : null);
78
+ if (!req || req === "all") return allSkills();
79
+ const want = req.split(",").map((s) => s.trim()).filter(Boolean);
80
+ const known = allSkills();
81
+ const bad = want.filter((w) => !known.includes(w));
82
+ if (bad.length) die(`Unknown skill(s): ${bad.join(", ")}\nRun: eng-os list`);
83
+ return want;
84
+ }
85
+
86
+ function installSkills(target, agentName, root, opts) {
87
+ const results = [];
88
+ for (const skill of selected()) {
89
+ const fm = frontmatter(skill);
90
+ const mode = fm.mode && MODE_SUFFIX_SUPPORT.has(agentName) ? `-${fm.mode}` : "";
91
+ const dest = path.join(root, `${target.projectSkills}${mode}`, skill);
92
+ results.push([skill, copyDir(path.join(SKILLS_DIR, skill), dest, opts)]);
93
+ }
94
+ return results;
95
+ }
96
+
97
+ function cmdInit() {
98
+ const agentName = opt("agent", DEFAULT_TARGET);
99
+ const agents = agentName === "all" ? Object.keys(TARGETS) : [agentName];
100
+ const root = base();
101
+ const opts = { force: flag("force"), link: flag("link") };
102
+
103
+ say(`${c.b}eng-os-kit ${pkg.version}${c.x} → ${root}\n`);
104
+
105
+ for (const name of agents) {
106
+ const target = resolveTarget(name);
107
+ say(`${c.b}${target.label}${c.x}`);
108
+ for (const [skill, status] of installSkills(target, name, root, opts)) {
109
+ status === "skipped"
110
+ ? warn(`${skill} ${c.d}(already present, use --force)${c.x}`)
111
+ : ok(`${skill} ${c.d}${status}${c.x}`);
112
+ }
113
+ const rulesDest = path.join(root, target.projectRules, target.rulesFile);
114
+ const st = copyFile(path.join(PKG_ROOT, "rules", "engineering-contract.md"), rulesDest, opts);
115
+ st === "skipped" ? warn(`${target.rulesFile} ${c.d}(already present)${c.x}`) : ok(`${path.relative(root, rulesDest)}`);
116
+ say("");
117
+ }
118
+
119
+ if (flag("global")) { ok("Global install done. Reload your editor to pick up new skills."); return; }
120
+
121
+ for (const dir of [".agent/state", ".agent/prompts", ".agent/plans", ".agent/audits", ".agent/verification", ".agent/reports", ".agent/templates"]) {
122
+ fs.mkdirSync(path.join(root, dir), { recursive: true });
123
+ }
124
+ for (const f of fs.readdirSync(path.join(PKG_ROOT, "templates"))) {
125
+ copyFile(path.join(PKG_ROOT, "templates", f), path.join(root, ".agent/templates", f), opts);
126
+ }
127
+ for (const f of fs.readdirSync(path.join(PKG_ROOT, "state"))) {
128
+ copyFile(path.join(PKG_ROOT, "state", f), path.join(root, ".agent/state", f), opts);
129
+ }
130
+ fs.mkdirSync(path.join(root, ".agent/scripts"), { recursive: true });
131
+ for (const f of fs.readdirSync(path.join(PKG_ROOT, "scripts"))) {
132
+ const to = path.join(root, ".agent/scripts", f);
133
+ copyFile(path.join(PKG_ROOT, "scripts", f), to, opts);
134
+ if (fs.existsSync(to)) fs.chmodSync(to, 0o755);
135
+ }
136
+ ok(".agent/ state, templates and scripts ready");
137
+ say(`\n${c.d}Next:${c.x} reload your editor, then ask the agent: "read the engineering contract and run discovery".`);
138
+ say(`${c.d}Enforce:${c.x} npx eng-os check`);
139
+ }
140
+
141
+ function cmdList() {
142
+ say(`${c.b}Skills in eng-os-kit ${pkg.version}${c.x}\n`);
143
+ for (const s of allSkills()) {
144
+ const fm = frontmatter(s);
145
+ say(`${c.b}${s}${c.x}${fm.mode ? c.d + " [mode: " + fm.mode + "]" + c.x : ""}`);
146
+ say(` ${c.d}${fm.description || ""}${c.x}\n`);
147
+ }
148
+ say(`${c.d}Install all: npx eng-os-kit init${c.x}`);
149
+ say(`${c.d}Install some: npx eng-os-kit add security-review test-strategy${c.x}`);
150
+ }
151
+
152
+ function cmdAdd() {
153
+ if (!positionals.length && !opt("skills", null)) die("Name at least one skill. Run: eng-os list");
154
+ cmdInit();
155
+ }
156
+
157
+ function cmdCheck() {
158
+ const root = base();
159
+ let failed = 0;
160
+ const run = (label, file, args = []) => {
161
+ const local = path.join(root, ".agent/scripts", file);
162
+ const script = fs.existsSync(local) ? local : path.join(PKG_ROOT, "scripts", file);
163
+ say(`\n${c.b}› ${label}${c.x}`);
164
+ const bin = file.endsWith(".mjs") ? process.execPath : "bash";
165
+ const r = spawnSync(bin, [script, ...args], { stdio: "inherit", cwd: root });
166
+ if (r.status !== 0) failed++;
167
+ };
168
+ run("Placeholder / dead-path audit", "placeholder-audit.sh");
169
+ run("Feature registry validation", "validate-registry.mjs");
170
+ if (failed) die(`${failed} check(s) failed. Nothing is PRODUCTION_READY until these pass.`);
171
+ say(`\n${c.g}All eng-os checks passed.${c.x}`);
172
+ }
173
+
174
+ function cmdDoctor() {
175
+ const root = base();
176
+ const agentName = opt("agent", DEFAULT_TARGET);
177
+ const target = resolveTarget(agentName);
178
+ say(`${c.b}eng-os doctor${c.x} ${c.d}(${target.label} @ ${root})${c.x}\n`);
179
+ const check = (label, p) => fs.existsSync(path.join(root, p)) ? ok(`${label} ${c.d}${p}${c.x}`) : warn(`${label} missing ${c.d}${p}${c.x}`);
180
+ check("skills", target.projectSkills);
181
+ check("rules", path.join(target.projectRules, target.rulesFile));
182
+ check("state", ".agent/state/feature-registry.json");
183
+ check("scripts", ".agent/scripts/placeholder-audit.sh");
184
+ const skillsParent = path.dirname(path.join(root, target.projectSkills));
185
+ const leaf = path.basename(target.projectSkills);
186
+ const installed = fs.existsSync(skillsParent)
187
+ ? fs.readdirSync(skillsParent, { withFileTypes: true })
188
+ .filter((d) => d.isDirectory() && d.name.startsWith(leaf))
189
+ .flatMap((d) => fs.readdirSync(path.join(skillsParent, d.name)))
190
+ : [];
191
+ const missing = allSkills().filter((s) => !installed.includes(s));
192
+ if (missing.length) warn(`not installed: ${missing.join(", ")}`);
193
+ say(`\n${c.d}Reload the editor after any skill change — Kilo Code only reliably picks up SKILL.md changes on reload.${c.x}`);
194
+ }
195
+
196
+ function cmdHelp() {
197
+ say(`${c.b}eng-os-kit${c.x} ${pkg.version} — engineering operating system for AI coding agents
198
+
199
+ ${c.b}Usage${c.x}
200
+ npx eng-os-kit init [options] install rules + all skills + .agent scaffolding
201
+ npx eng-os-kit add <skill...> install specific skills only
202
+ npx eng-os-kit list list bundled skills and their triggers
203
+ npx eng-os-kit check run the enforcement scripts (CI-safe)
204
+ npx eng-os-kit doctor show what is installed where
205
+
206
+ ${c.b}Options${c.x}
207
+ --agent <name> kilocode (default) | claude | roo | cursor | codex | all
208
+ --global install to your home directory instead of this project
209
+ --skills a,b comma separated subset
210
+ --link symlink skills instead of copying (keeps them updatable)
211
+ --force overwrite existing files
212
+ --cwd <path> target project directory
213
+
214
+ ${c.b}Examples${c.x}
215
+ npx eng-os-kit init # Kilo Code, this project
216
+ npx eng-os-kit init --agent kilocode --global # every project on this machine
217
+ npx eng-os-kit init --link # stay in sync with npm updates
218
+ npx eng-os-kit add security-review --agent roo
219
+ `);
220
+ }
221
+
222
+ ({ init: cmdInit, add: cmdAdd, list: cmdList, check: cmdCheck, doctor: cmdDoctor, help: cmdHelp }[cmd] || cmdHelp)();
@@ -0,0 +1,49 @@
1
+ // Where each agent expects rules and skills to live.
2
+ // Kilo Code: https://kilo.ai/docs/features/skills (.kilocode/skills, .kilocode/rules)
3
+ export const TARGETS = {
4
+ kilocode: {
5
+ label: "Kilo Code",
6
+ projectSkills: ".kilocode/skills",
7
+ globalSkills: ".kilocode/skills",
8
+ projectRules: ".kilocode/rules",
9
+ rulesFile: "00-engineering-contract.md",
10
+ globalBase: ".kilocode"
11
+ },
12
+ claude: {
13
+ label: "Claude Code",
14
+ projectSkills: ".claude/skills",
15
+ globalSkills: ".claude/skills",
16
+ projectRules: ".",
17
+ rulesFile: "CLAUDE.md",
18
+ globalBase: ".claude"
19
+ },
20
+ roo: {
21
+ label: "Roo Code",
22
+ projectSkills: ".roo/skills",
23
+ globalSkills: ".roo/skills",
24
+ projectRules: ".roo/rules",
25
+ rulesFile: "00-engineering-contract.md",
26
+ globalBase: ".roo"
27
+ },
28
+ cursor: {
29
+ label: "Cursor",
30
+ projectSkills: ".cursor/skills",
31
+ globalSkills: ".cursor/skills",
32
+ projectRules: ".",
33
+ rulesFile: "AGENTS.md",
34
+ globalBase: ".cursor"
35
+ },
36
+ codex: {
37
+ label: "Codex / generic Agent Skills",
38
+ projectSkills: ".agents/skills",
39
+ globalSkills: ".agents/skills",
40
+ projectRules: ".",
41
+ rulesFile: "AGENTS.md",
42
+ globalBase: ".agents"
43
+ }
44
+ };
45
+
46
+ export const DEFAULT_TARGET = "kilocode";
47
+
48
+ // Mode-scoped skills for agents that support skills-<mode> (Kilo Code, Roo).
49
+ export const MODE_SUFFIX_SUPPORT = new Set(["kilocode", "roo"]);
package/package.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "@michaelmusyoka/eng-os-kit",
3
+ "version": "1.0.0",
4
+ "description": "Production engineering operating system for AI coding agents: rules, Agent Skills, templates and enforcement scripts. Installs into Kilo Code, Claude Code, Roo, Cursor or any Agent Skills compatible agent.",
5
+ "keywords": ["kilocode", "kilo-code", "agent-skills", "skill", "claude-code", "roo-code", "ai-agent", "engineering-standards"],
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "engines": { "node": ">=18" },
9
+ "bin": { "eng-os": "bin/eng-os.mjs" },
10
+ "files": ["bin", "lib", "rules", "skills", "templates", "scripts", "state", "README.md"],
11
+ "scripts": {
12
+ "selftest": "node bin/eng-os.mjs list && node bin/eng-os.mjs --help"
13
+ }
14
+ }
@@ -0,0 +1,51 @@
1
+ # Engineering Contract
2
+
3
+ Always in context. Everything else loads on demand as a skill.
4
+
5
+ ## Precedence
6
+ 1. Explicit user instruction
7
+ 2. This contract
8
+ 3. Approved implementation prompt in `.agent/prompts/`
9
+ 4. Repository architecture docs and conventions
10
+ 5. Installed framework/package documentation
11
+ 6. General judgement
12
+
13
+ Surface material conflicts. Do not resolve them silently.
14
+
15
+ ## Six rules that never bend
16
+ 1. **Inspect before editing.** Read the real files, schema, routes and tests. Do not assume structure.
17
+ 2. **Plan before production code.** Anything touching auth, money, migrations, external integrations, or more than three files needs an approved prompt first (skill: `implementation-prompt`). Smaller changes may proceed directly.
18
+ 3. **Never claim a check you did not run.** No "should work". Evidence or nothing (skill: `verification-evidence`).
19
+ 4. **Never fake production behaviour.** No mocks, stubbed success, hardcoded metrics or UI-only state in a production path.
20
+ 5. **Never weaken a test, type check, lint rule or security control to make something pass.** Fix the cause.
21
+ 6. **Never move a secret into client code, and never trust client-side validation for security.**
22
+
23
+ ## Statuses
24
+ `PLANNED → IN_PROGRESS → IMPLEMENTED → VERIFIED → PRODUCTION_READY`, plus `BLOCKED`.
25
+
26
+ `IMPLEMENTED` means code exists. It never means done. Only `VERIFIED` (evidence recorded) and `PRODUCTION_READY` (release gate passed) do.
27
+
28
+ Track every feature in `.agent/state/feature-registry.json`. Conversation memory is not project state.
29
+
30
+ ## Blocked
31
+ When a dependency, credential or decision is missing, stop and report: blocker, impact, what resolution is needed, what you could still verify. Never invent a dependency response.
32
+
33
+ ## Vertical slices
34
+ UI → route/API → authentication → authorization → validation → service → persistence → integration → events → UI state. A UI-only or API-only implementation of a user-facing requirement is incomplete.
35
+
36
+ ## Final report format
37
+ ```
38
+ ### What I did
39
+ - short bullets
40
+
41
+ ### Test
42
+ 1. exact command or manual step
43
+ 2. actual result
44
+
45
+ ### Needs your attention
46
+ - decision, blocker, or None
47
+ ```
48
+ Keep it short. Detail belongs in `.agent/prompts/`, `.agent/verification/` and `.agent/audits/`.
49
+
50
+ ## Skills available
51
+ `repo-inspection`, `implementation-prompt`, `api-database-contract`, `security-review`, `test-strategy`, `traceability-audit`, `verification-evidence`, `release-gate`, `code-review`, `incident-response`, `signature-dark-ui`. Load the one that fits; do not work from memory of these standards.
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env bash
2
+ # Runs a command and records real output as evidence.
3
+ # Usage: .agent/scripts/capture-evidence.sh F-001 "npm test -- --run"
4
+ set -uo pipefail
5
+
6
+ FEATURE="${1:?usage: capture-evidence.sh <feature-id> \"<command>\"}"
7
+ CMD="${2:?usage: capture-evidence.sh <feature-id> \"<command>\"}"
8
+
9
+ DIR=".agent/verification/${FEATURE}"
10
+ mkdir -p "$DIR"
11
+ STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
12
+ SLUG="$(printf '%s' "$CMD" | tr -cs 'a-zA-Z0-9' '-' | cut -c1-40 | sed 's/-$//')"
13
+ OUT="${DIR}/${STAMP}-${SLUG}.log"
14
+ SHA="$(git rev-parse HEAD 2>/dev/null || echo 'not-a-git-repo')"
15
+
16
+ {
17
+ echo "feature: $FEATURE"
18
+ echo "command: $CMD"
19
+ echo "commit: $SHA"
20
+ echo "timestamp: $STAMP"
21
+ echo "host: $(uname -sm)"
22
+ echo "---"
23
+ } > "$OUT"
24
+
25
+ set +e
26
+ bash -lc "$CMD" 2>&1 | tail -400 >> "$OUT"
27
+ CODE="${PIPESTATUS[0]}"
28
+ set -e
29
+
30
+ { echo "---"; echo "exit_code: $CODE"; } >> "$OUT"
31
+
32
+ if [ "$CODE" -eq 0 ]; then
33
+ echo "✓ PASS exit 0 → $OUT"
34
+ else
35
+ echo "✗ FAIL exit $CODE → $OUT"
36
+ fi
37
+ echo "Add this path to the feature's \"evidence\" array in .agent/state/feature-registry.json"
38
+ exit "$CODE"
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env bash
2
+ # Fails when unfinished production behaviour is committed.
3
+ # Usage: .agent/scripts/placeholder-audit.sh [path] (default: repo root)
4
+ set -uo pipefail
5
+
6
+ ROOT="${1:-.}"
7
+ STRICT_PATTERN='TODO|FIXME|XXX|HACK|placeholder|coming soon|not implemented|NotImplemented|dummy|FAKE_|hardcoded'
8
+ MOCK_PATTERN='mockResolvedValue|jest\.mock|MSW_ENABLED|process\.env\.MOCK|useMockData|__mocks__/'
9
+ DEADLINK_PATTERN='href=["'"'"']#["'"'"']|href=["'"'"']["'"'"']|to=["'"'"']#["'"'"']'
10
+ DEBUG_PATTERN='console\.log|debugger;|print\(.*DEBUG'
11
+ SECRET_PATTERN='(AKIA[0-9A-Z]{16})|(sk_live_[0-9a-zA-Z]{10,})|(-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----)|(ghp_[0-9a-zA-Z]{20,})'
12
+
13
+ EXCLUDES=(--exclude-dir=node_modules --exclude-dir=.git --exclude-dir=dist --exclude-dir=build
14
+ --exclude-dir=.next --exclude-dir=coverage --exclude-dir=vendor --exclude-dir=.venv
15
+ --exclude-dir=__tests__ --exclude-dir=tests --exclude-dir=test --exclude-dir=e2e
16
+ --exclude-dir=.agent --exclude-dir=.kilocode --exclude-dir=.claude
17
+ --exclude=*.test.* --exclude=*.spec.* --exclude=*.md --exclude=*.lock --exclude=*.map
18
+ --exclude=placeholder-audit.sh --exclude=validate-registry.mjs --exclude=capture-evidence.sh)
19
+
20
+ fail=0
21
+ scan() {
22
+ local label="$1" pattern="$2" severity="$3"
23
+ local hits
24
+ hits="$(grep -rInE "$pattern" "$ROOT" "${EXCLUDES[@]}" 2>/dev/null || true)"
25
+ if [ -n "$hits" ]; then
26
+ local n; n="$(printf '%s\n' "$hits" | wc -l | tr -d ' ')"
27
+ echo "[$severity] $label — $n occurrence(s)"
28
+ printf '%s\n' "$hits" | head -40 | sed 's/^/ /'
29
+ [ "$n" -gt 40 ] && echo " ... $((n - 40)) more"
30
+ [ "$severity" = "FAIL" ] && fail=1
31
+ echo
32
+ else
33
+ echo "[ok] $label"
34
+ fi
35
+ }
36
+
37
+ echo "Placeholder / dead-path audit — $(date -u +%Y-%m-%dT%H:%M:%SZ)"
38
+ echo "Scanning: $ROOT (production paths; tests and docs excluded)"
39
+ echo
40
+ scan "committed secrets" "$SECRET_PATTERN" "FAIL"
41
+ scan "unfinished markers" "$STRICT_PATTERN" "FAIL"
42
+ scan "mocks in production paths" "$MOCK_PATTERN" "FAIL"
43
+ scan "dead links / empty hrefs" "$DEADLINK_PATTERN" "WARN"
44
+ scan "debug output" "$DEBUG_PATTERN" "WARN"
45
+
46
+ echo
47
+ if [ "$fail" -ne 0 ]; then
48
+ echo "RESULT: FAIL — resolve each FAIL occurrence, or document it in .agent/state/known-issues.md and exclude it deliberately."
49
+ exit 1
50
+ fi
51
+ echo "RESULT: PASS"
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+ // Validates .agent/state/feature-registry.json: schema-ish checks plus the rules
3
+ // that actually catch false completion claims. No dependencies.
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+
7
+ const root = process.argv[2] || process.cwd();
8
+ const file = path.join(root, ".agent/state/feature-registry.json");
9
+ const STATUSES = ["PLANNED", "IN_PROGRESS", "IMPLEMENTED", "VERIFIED", "PRODUCTION_READY", "BLOCKED"];
10
+ const NEEDS_EVIDENCE = ["VERIFIED", "PRODUCTION_READY"];
11
+
12
+ if (!fs.existsSync(file)) {
13
+ console.error(`✗ missing ${path.relative(root, file)} — run: npx eng-os-kit init`);
14
+ process.exit(1);
15
+ }
16
+
17
+ let data;
18
+ try { data = JSON.parse(fs.readFileSync(file, "utf8")); }
19
+ catch (e) { console.error(`✗ invalid JSON: ${e.message}`); process.exit(1); }
20
+
21
+ const errors = [];
22
+ const warnings = [];
23
+ const features = data.features;
24
+
25
+ if (!Array.isArray(features)) {
26
+ console.error("✗ top-level \"features\" must be an array");
27
+ process.exit(1);
28
+ }
29
+
30
+ const seen = new Set();
31
+ for (const [i, f] of features.entries()) {
32
+ const at = f?.id || `features[${i}]`;
33
+ const need = (k, test, msg) => { if (!test) errors.push(`${at}: ${msg || `missing or invalid "${k}"`}`); };
34
+
35
+ need("id", typeof f.id === "string" && /^F-\d{3,}$/.test(f.id), `"id" must look like F-001`);
36
+ if (seen.has(f.id)) errors.push(`${at}: duplicate id`);
37
+ seen.add(f.id);
38
+ need("title", typeof f.title === "string" && f.title.length > 2);
39
+ need("criticality", ["critical", "standard"].includes(f.criticality), `"criticality" must be "critical" or "standard"`);
40
+ need("status", STATUSES.includes(f.status), `"status" must be one of ${STATUSES.join(", ")}`);
41
+ need("requirements", Array.isArray(f.requirements) && f.requirements.length > 0, `needs at least one requirement id`);
42
+ need("acceptanceCriteria", Array.isArray(f.acceptanceCriteria) && f.acceptanceCriteria.length > 0, `needs at least one acceptance criterion`);
43
+ need("tests", Array.isArray(f.tests));
44
+ need("evidence", Array.isArray(f.evidence));
45
+
46
+ if (NEEDS_EVIDENCE.includes(f.status)) {
47
+ if (!f.evidence?.length) errors.push(`${at}: status ${f.status} with no evidence — evidence is required, not optional`);
48
+ if (!f.tests?.length) errors.push(`${at}: status ${f.status} with no tests listed`);
49
+ for (const e of f.evidence || []) {
50
+ const p = path.join(root, e);
51
+ if (!e.startsWith("http") && !fs.existsSync(p)) errors.push(`${at}: evidence path does not exist: ${e}`);
52
+ }
53
+ }
54
+ if (f.status === "PRODUCTION_READY" && f.criticality === "critical" && !(f.security || []).length) {
55
+ errors.push(`${at}: critical feature marked PRODUCTION_READY with no security checks recorded`);
56
+ }
57
+ if (f.status === "BLOCKED" && !f.notes) warnings.push(`${at}: BLOCKED without notes explaining the blocker`);
58
+ if (f.criticality === "critical" && f.status === "IMPLEMENTED") warnings.push(`${at}: critical feature IMPLEMENTED but not VERIFIED`);
59
+ }
60
+
61
+ const count = (s) => features.filter((f) => f.status === s).length;
62
+ console.log(`Feature registry: ${features.length} feature(s)`);
63
+ console.log(STATUSES.map((s) => ` ${s}: ${count(s)}`).join("\n"));
64
+ if (warnings.length) { console.log("\nWarnings:"); warnings.forEach((w) => console.log(` ! ${w}`)); }
65
+ if (errors.length) {
66
+ console.error("\nErrors:");
67
+ errors.forEach((e) => console.error(` ✗ ${e}`));
68
+ console.error(`\nRESULT: FAIL (${errors.length} error(s))`);
69
+ process.exit(1);
70
+ }
71
+ console.log("\nRESULT: PASS");
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: api-database-contract
3
+ description: Standards for designing endpoints, error models, database entities, constraints, indexes, idempotency and migrations. Use this whenever adding or changing an API route, server action, database table, column, or migration, when defining error responses, and when a state-changing operation could be retried. Load before writing any schema or endpoint.
4
+ ---
5
+
6
+ # API and Database Contracts
7
+
8
+ ## Every endpoint defines
9
+ method, path, purpose, authentication, permission, request schema, validation, response schema, error cases, rate limit, timeout, idempotency behaviour, pagination/filtering/sorting, audit behaviour.
10
+
11
+ ## Error model
12
+ | Code | Meaning |
13
+ |---|---|
14
+ | 400 | malformed request |
15
+ | 401 | unauthenticated |
16
+ | 403 | authenticated but not permitted |
17
+ | 404 | missing, or hidden for authorization reasons |
18
+ | 409 | conflict / concurrent update |
19
+ | 422 | semantically invalid |
20
+ | 429 | rate limited |
21
+ | 500 | internal failure |
22
+ | 503 | dependency unavailable |
23
+
24
+ Never leak stack traces, SQL, secrets, internal paths or provider payloads. Return a stable error `code` string alongside the message so clients can branch without string matching.
25
+
26
+ ## Every entity defines
27
+ ownership, primary key, relationships, nullability, unique constraints, indexes supporting its real queries, audit fields, retention, deletion behaviour (hard vs soft, and what cascades).
28
+
29
+ Use database constraints for critical integrity rules. Application-level validation must not be the only protection — a unique index is the only thing that actually prevents a duplicate under concurrency.
30
+
31
+ ## Idempotency
32
+ Any state-changing operation that an external system, a retry, or an impatient user can repeat needs a duplicate-safety story. Options: idempotency key with stored response, natural unique constraint, or conditional update on a version column. Choose one explicitly and test:
33
+ - same request + same key → one logical operation, same response
34
+ - different key → separate operation where permitted
35
+ - concurrent identical requests → one winner, no partial state
36
+
37
+ ## Migrations
38
+ Versioned, reproducible from empty, tested, reviewed, safe for existing data. Before a production migration assess: lock duration, downtime, backfill volume, rollback path, and whether old and new application versions can both run against the intermediate schema. Assume no migration is safely reversible until you have reversed it.