holycodex 0.2.1

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 (93) hide show
  1. package/LICENSE.md +82 -0
  2. package/README.md +107 -0
  3. package/THIRD-PARTY-NOTICES.md +7 -0
  4. package/bin/holycodex.js +2 -0
  5. package/marketplace.json +12 -0
  6. package/package.json +59 -0
  7. package/plugin/.codex-plugin/plugin.json +29 -0
  8. package/plugin/.mcp.json +8 -0
  9. package/plugin/agents/explorer.toml +6 -0
  10. package/plugin/agents/librarian.toml +6 -0
  11. package/plugin/agents/worker.toml +6 -0
  12. package/plugin/hooks/hooks.json +93 -0
  13. package/plugin/runtime/bootstrap.js +23 -0
  14. package/plugin/runtime/cli.js +233 -0
  15. package/plugin/runtime/git-bash.js +359 -0
  16. package/plugin/runtime/lsp.js +3674 -0
  17. package/plugin/runtime/rules.js +146 -0
  18. package/plugin/runtime/src-tRIOClWZ.js +209 -0
  19. package/plugin/skills/ast-grep/LICENSE +21 -0
  20. package/plugin/skills/ast-grep/SKILL.md +20 -0
  21. package/plugin/skills/ast-grep/references/cli.md +3 -0
  22. package/plugin/skills/ast-grep/references/install.md +3 -0
  23. package/plugin/skills/ast-grep/references/patterns.md +3 -0
  24. package/plugin/skills/ast-grep/references/pitfalls.md +3 -0
  25. package/plugin/skills/ast-grep/references/recipes.md +9 -0
  26. package/plugin/skills/ast-grep/references/sgconfig.md +3 -0
  27. package/plugin/skills/ast-grep/references/yaml-rules.md +3 -0
  28. package/plugin/skills/caveman/LICENSE +21 -0
  29. package/plugin/skills/caveman/SKILL.md +84 -0
  30. package/plugin/skills/comment-checker/SKILL.md +16 -0
  31. package/plugin/skills/compress/SKILL.md +26 -0
  32. package/plugin/skills/debugging/SKILL.md +23 -0
  33. package/plugin/skills/debugging/references/runtimes/README.md +9 -0
  34. package/plugin/skills/debugging/references/tools/README.md +8 -0
  35. package/plugin/skills/define-goal/LICENSE.txt +201 -0
  36. package/plugin/skills/define-goal/SKILL.md +36 -0
  37. package/plugin/skills/frontend/ATTRIBUTION.md +218 -0
  38. package/plugin/skills/frontend/LICENSE-Apache-2.0.txt +201 -0
  39. package/plugin/skills/frontend/SKILL.md +42 -0
  40. package/plugin/skills/frontend/references/perfection/README.md +5 -0
  41. package/plugin/skills/frontend/references/perfection/react-perf-tooling.md +3 -0
  42. package/plugin/skills/frontend/references/ui-ux-db/README.md +5 -0
  43. package/plugin/skills/frontend/references/ui-ux-db/data/charts.csv +26 -0
  44. package/plugin/skills/frontend/references/ui-ux-db/data/colors.csv +162 -0
  45. package/plugin/skills/frontend/references/ui-ux-db/data/icons.csv +106 -0
  46. package/plugin/skills/frontend/references/ui-ux-db/data/landing.csv +35 -0
  47. package/plugin/skills/frontend/references/ui-ux-db/data/products.csv +162 -0
  48. package/plugin/skills/frontend/references/ui-ux-db/data/react-performance.csv +45 -0
  49. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/astro.csv +54 -0
  50. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/flutter.csv +53 -0
  51. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/html-tailwind.csv +56 -0
  52. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/jetpack-compose.csv +53 -0
  53. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/nextjs.csv +53 -0
  54. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/nuxt-ui.csv +51 -0
  55. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/nuxtjs.csv +59 -0
  56. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/react-native.csv +52 -0
  57. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/react.csv +54 -0
  58. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/shadcn.csv +61 -0
  59. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/svelte.csv +54 -0
  60. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/swiftui.csv +51 -0
  61. package/plugin/skills/frontend/references/ui-ux-db/data/stacks/vue.csv +50 -0
  62. package/plugin/skills/frontend/references/ui-ux-db/data/styles.csv +85 -0
  63. package/plugin/skills/frontend/references/ui-ux-db/data/typography.csv +74 -0
  64. package/plugin/skills/frontend/references/ui-ux-db/data/ui-reasoning.csv +162 -0
  65. package/plugin/skills/frontend/references/ui-ux-db/data/ux-guidelines.csv +100 -0
  66. package/plugin/skills/frontend/references/ui-ux-db/data/web-interface.csv +31 -0
  67. package/plugin/skills/frontend/references/ui-ux-db/scripts/core.py +262 -0
  68. package/plugin/skills/frontend/references/ui-ux-db/scripts/design_system.py +1148 -0
  69. package/plugin/skills/frontend/references/ui-ux-db/scripts/search.py +114 -0
  70. package/plugin/skills/handoff/SKILL.md +10 -0
  71. package/plugin/skills/lsp/SKILL.md +35 -0
  72. package/plugin/skills/lsp-setup/SKILL.md +18 -0
  73. package/plugin/skills/lsp-setup/scripts/detect-lsp.ts +233 -0
  74. package/plugin/skills/lsp-setup/scripts/lsp-server-table.ts +188 -0
  75. package/plugin/skills/lsp-setup/scripts/tsconfig.json +17 -0
  76. package/plugin/skills/lsp-setup/scripts/verify-lsp.ts +166 -0
  77. package/plugin/skills/plan/SKILL.md +14 -0
  78. package/plugin/skills/plan-review/SKILL.md +12 -0
  79. package/plugin/skills/programming/SKILL.md +35 -0
  80. package/plugin/skills/programming/references/code-smells.md +3 -0
  81. package/plugin/skills/programming/references/go/README.md +3 -0
  82. package/plugin/skills/programming/references/logging.md +3 -0
  83. package/plugin/skills/programming/references/python/README.md +3 -0
  84. package/plugin/skills/programming/references/rust/README.md +3 -0
  85. package/plugin/skills/programming/references/rust-ub/README.md +3 -0
  86. package/plugin/skills/programming/references/typescript/README.md +3 -0
  87. package/plugin/skills/refactor/SKILL.md +21 -0
  88. package/plugin/skills/remove-ai-slops/SKILL.md +20 -0
  89. package/plugin/skills/rules/SKILL.md +16 -0
  90. package/plugin/skills/security-research/SKILL.md +38 -0
  91. package/plugin/skills/tdd/SKILL.md +24 -0
  92. package/plugin/skills/tdd/mocking.md +60 -0
  93. package/plugin/skills/tdd/tests.md +77 -0
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env bun
2
+ // verify-lsp.ts <file> [--timeout=ms] — perform a real LSP diagnostics roundtrip
3
+ // for <file> through the lsp-tools-mcp engine and report ok/fail with error text.
4
+ // The engine source is located by walking up from this script and the cwd, so
5
+ // run it inside the HolyCodex repository (where packages/lsp-core/src exists).
6
+
7
+ import { existsSync, statSync } from "node:fs";
8
+ import { dirname, isAbsolute, join, resolve } from "node:path";
9
+ import process from "node:process";
10
+ import { fileURLToPath, pathToFileURL } from "node:url";
11
+
12
+ const ENGINE_TOOLS = "packages/lsp-core/src/tools.ts";
13
+ const ENGINE_CONTEXT = "packages/lsp-core/src/request-context.ts";
14
+ const ENGINE_MANAGER = "packages/lsp-core/src/lsp/manager.ts";
15
+ const DEFAULT_TIMEOUT_MS = 60_000;
16
+
17
+ interface ToolExecutionResult {
18
+ readonly content: ReadonlyArray<{ readonly type: "text"; readonly text: string }>;
19
+ readonly isError?: boolean;
20
+ readonly details?: unknown;
21
+ }
22
+
23
+ interface DiagnosticsDetails {
24
+ readonly mode: "file" | "directory";
25
+ readonly totalDiagnostics: number;
26
+ readonly error?: string;
27
+ readonly errorKind?: "missing_dependency" | "no_files" | "invalid_path";
28
+ }
29
+
30
+ interface ToolsModule {
31
+ readonly executeLspDiagnostics: (
32
+ params: Record<string, unknown>,
33
+ signal?: AbortSignal,
34
+ ) => Promise<ToolExecutionResult>;
35
+ }
36
+
37
+ interface ContextModule {
38
+ readonly runWithRequestContext: <T>(
39
+ context: { cwd?: string; env?: Record<string, string> },
40
+ fn: () => T,
41
+ ) => T;
42
+ }
43
+
44
+ interface ManagerModule {
45
+ readonly disposeDefaultLspManager: () => Promise<void>;
46
+ }
47
+
48
+ function findUp(relativeTarget: string): string | null {
49
+ const starts = [dirname(fileURLToPath(import.meta.url)), process.cwd()];
50
+ for (const start of starts) {
51
+ let current = start;
52
+ while (true) {
53
+ const candidate = join(current, relativeTarget);
54
+ if (existsSync(candidate)) return candidate;
55
+ const parent = dirname(current);
56
+ if (parent === current) break;
57
+ current = parent;
58
+ }
59
+ }
60
+ return null;
61
+ }
62
+
63
+ function buildEnv(): Record<string, string> {
64
+ const env: Record<string, string> = {};
65
+ for (const [key, value] of Object.entries(process.env)) {
66
+ if (value !== undefined) env[key] = value;
67
+ }
68
+ return env;
69
+ }
70
+
71
+ function isDiagnosticsDetails(value: unknown): value is DiagnosticsDetails {
72
+ return (
73
+ typeof value === "object" && value !== null && "mode" in value && "totalDiagnostics" in value
74
+ );
75
+ }
76
+
77
+ async function loadModule<T>(relativeTarget: string): Promise<T> {
78
+ const path = findUp(relativeTarget);
79
+ if (path === null) {
80
+ throw new EngineNotFoundError(relativeTarget);
81
+ }
82
+ return (await import(pathToFileURL(path).href)) as T;
83
+ }
84
+
85
+ class EngineNotFoundError extends Error {
86
+ constructor(public readonly target: string) {
87
+ super(
88
+ `lsp-tools-mcp engine not found (looked for ${target}). Run verify-lsp.ts inside the HolyCodex repository.`,
89
+ );
90
+ this.name = "EngineNotFoundError";
91
+ }
92
+ }
93
+
94
+ function parseTimeout(args: readonly string[]): number {
95
+ const flag = args.find((arg) => arg.startsWith("--timeout="));
96
+ if (flag === undefined) return DEFAULT_TIMEOUT_MS;
97
+ const parsed = Number.parseInt(flag.slice("--timeout=".length), 10);
98
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_TIMEOUT_MS;
99
+ }
100
+
101
+ async function run(filePath: string, timeoutMs: number): Promise<number> {
102
+ const tools = await loadModule<ToolsModule>(ENGINE_TOOLS);
103
+ const context = await loadModule<ContextModule>(ENGINE_CONTEXT);
104
+ const manager = await loadModule<ManagerModule>(ENGINE_MANAGER);
105
+ const absolute = isAbsolute(filePath) ? filePath : resolve(process.cwd(), filePath);
106
+
107
+ try {
108
+ const signal = AbortSignal.timeout(timeoutMs);
109
+ const result = await context.runWithRequestContext(
110
+ { cwd: process.cwd(), env: buildEnv() },
111
+ () => tools.executeLspDiagnostics({ filePath: absolute, severity: "all" }, signal),
112
+ );
113
+ const details = isDiagnosticsDetails(result.details) ? result.details : null;
114
+ const text = result.content.map((part) => part.text).join("\n");
115
+
116
+ if (details?.errorKind === "missing_dependency") {
117
+ process.stdout.write(`FAIL ${absolute}: language server not installed\n${text}\n`);
118
+ return 1;
119
+ }
120
+ if (
121
+ result.isError === true ||
122
+ details?.errorKind === "invalid_path" ||
123
+ details?.errorKind === "no_files"
124
+ ) {
125
+ process.stdout.write(`FAIL ${absolute}: ${details?.error ?? text}\n`);
126
+ return 1;
127
+ }
128
+
129
+ const count = details?.totalDiagnostics ?? 0;
130
+ process.stdout.write(
131
+ `OK ${absolute}: LSP roundtrip succeeded (${count} diagnostic(s))\n${text}\n`,
132
+ );
133
+ return 0;
134
+ } finally {
135
+ await manager.disposeDefaultLspManager();
136
+ }
137
+ }
138
+
139
+ async function main(): Promise<void> {
140
+ const args = process.argv.slice(2);
141
+ const filePath = args.find((arg) => !arg.startsWith("--"));
142
+ if (filePath === undefined) {
143
+ process.stderr.write("Usage: bun verify-lsp.ts <file> [--timeout=ms]\n");
144
+ process.exit(2);
145
+ }
146
+ if (!existsSync(filePath) || !statSync(filePath).isFile()) {
147
+ process.stderr.write(`verify-lsp: not a file: ${filePath}\n`);
148
+ process.exit(2);
149
+ }
150
+
151
+ try {
152
+ const code = await run(filePath, parseTimeout(args));
153
+ process.exit(code);
154
+ } catch (error) {
155
+ if (error instanceof EngineNotFoundError) {
156
+ process.stderr.write(`SKIP: ${error.message}\n`);
157
+ process.exit(3);
158
+ }
159
+ process.stderr.write(
160
+ `FAIL ${filePath}: ${error instanceof Error ? error.message : String(error)}\n`,
161
+ );
162
+ process.exit(1);
163
+ }
164
+ }
165
+
166
+ await main();
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: plan
3
+ description: Write a concise executable plan. Use only when the user explicitly asks for a plan before implementation.
4
+ ---
5
+
6
+ # Plan
7
+
8
+ On activation, first user-visible line must be:
9
+
10
+ **PLAN MODE ACTIVATED**
11
+
12
+ Main agent writes plan. No subagent, reviewer, evidence directory, execution waves, commit ritual, or ceremony unless user asks.
13
+
14
+ Inspect enough repo context first. Then give ordered steps. Each step names relevant files or surface, exact change, expected outcome, smallest proof. Mark dependencies and user decisions only when material. Preserve architecture and scope. Stop when plan is executable.
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: plan-review
3
+ description: Review and repair an existing plan once. Use only when the user explicitly asks to review, critique, validate, or improve a plan.
4
+ ---
5
+
6
+ # Plan Review
7
+
8
+ On activation, first user-visible line must be:
9
+
10
+ **PLAN REVIEW ACTIVATED**
11
+
12
+ One pass. Check plan against request and repo facts. Find only real blockers: wrong seam, missing dependency, unsafe mutation, unverifiable step, incompatible contract, omitted required scope. Repair directly. Keep good parts. No reviewer agent, scoring theater, evidence folder, or second review loop. Stop after corrected executable plan.
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: programming
3
+ description: Strict Python, Rust, TypeScript, and Go implementation. Use whenever creating or changing .py, .pyi, .rs, .ts, .tsx, .mts, .cts, or .go files.
4
+ ---
5
+
6
+ # Programming
7
+
8
+ Use for `.py`, `.pyi`, `.rs`, `.ts`, `.tsx`, `.mts`, `.cts`, `.go`, or matching project manifest.
9
+
10
+ Before code, read language `references/<language>/README.md`; load only linked topic needed. Read `references/logging.md` only when touching logs. Rust unsafe/FFI also loads all `references/rust-ub/`.
11
+
12
+ ## Core
13
+
14
+ - Best code: none, existing helper, standard API, native feature, installed dependency, one line, then new code.
15
+ - Trace real flow and callers. Fix shared root seam once.
16
+ - Parse untrusted input once at boundary. Interior stays typed.
17
+ - Make illegal states unrepresentable. Distinct primitives get distinct types.
18
+ - Immutable default. No parameter mutation without explicit purpose.
19
+ - Exhaustive variant handling.
20
+ - No untyped escape, ignored diagnostics, non-null assertion, unchecked cast, panic/unwrap in library path.
21
+ - Typed errors. Catch only expected errors; unknown errors propagate to boundary.
22
+ - Existing project stack and logger win.
23
+ - No helper for one caller. No speculative abstraction.
24
+
25
+ ## Test
26
+
27
+ Public behavior red first. Confirm intended failure. Minimum green. Refactor. Use real object or fake before mock. Deterministic fixture; no sleep. At least one end-to-end user outcome for a new feature. Run smallest test in loop.
28
+
29
+ ## Size
30
+
31
+ After write, measure pure LOC. Under 200 healthy; 200–250 warn; over 250 split unless generated table or documented indivisible state machine. Function over three independent parameters needs named domain input or specific reason.
32
+
33
+ ## Finish
34
+
35
+ Run project formatter, linter, strict type checker, targeted tests, then proportional broader gate. Review: one responsibility; typed boundary; exhaustive variants; no escape hatch; no defensive duplicate layer; no one-off helper; regression test exists; no redundant post-action verification; positive names; logging matches project.
@@ -0,0 +1,3 @@
1
+ # Code smells
2
+
3
+ Reject duplicate validation, one-call helpers, boolean mode flags, primitive obsession, variant `if` chains, catch-and-rethrow noise, speculative fallback, hidden mutation, global state, wide interfaces, oversized modules, comments narrating code, and tests coupled to private structure. Fix only smell in task scope; lock behavior first.
@@ -0,0 +1,3 @@
1
+ # Go
2
+
3
+ Preserve module stack. Greenfield: current Go, gofmt/gofumpt, `go vet`, golangci-lint, tests with race detector when concurrency touched. Accept context first for cancellable work. Concrete inputs, narrow consumer-owned interfaces, explicit zero-value semantics. Wrap errors with `%w`; use `errors.Is/As`. Close owned resources. No panic for expected failure, goroutine without owner/stop path, copied mutex, hidden global state, `interface{}` escape, or sleep-based test. Table tests only when cases share one contract. Run format, vet/lint, targeted tests; `-race` for concurrent code.
@@ -0,0 +1,3 @@
1
+ # Logging
2
+
3
+ Use existing structured logger. Log once at ownership boundary, not every layer. Include stable event name and useful IDs; exclude secrets, tokens, raw personal data, huge payloads. Error logs retain typed cause and operation. Debug logs must not be required for correctness. Avoid string interpolation when logger supports fields.
@@ -0,0 +1,3 @@
1
+ # Python
2
+
3
+ Preserve workspace toolchain; greenfield prefers `uv`, Python 3.12+, Ruff, basedpyright, pytest. Type every public boundary. Parse external data with Pydantic v2 or existing schema layer. Prefer frozen dataclasses/models, protocols, pathlib, context managers, explicit async ownership, structured concurrency. No `Any`, bare `except`, mutable default, import side effect, silent fallback, or blocking I/O in async path. Use typed domain errors; preserve causes with `raise ... from`. Test public behavior with deterministic fixtures. Run formatter/lint, strict typecheck, targeted pytest.
@@ -0,0 +1,3 @@
1
+ # Rust
2
+
3
+ Preserve crate choices. Greenfield: stable edition, rustfmt, Clippy warnings denied, cargo test. Model states with enums/newtypes; borrow before clone; iterator when clearer. Libraries return typed `thiserror` errors; applications may add `anyhow` context at boundary. No `unwrap`, `expect`, panic, ignored `Result`, needless clone, blocking call in async runtime, or unbounded task. Use cancellation-aware structured tasks. Test public behavior; add property tests only for real invariants. Unsafe/FFI also loads `../rust-ub/README.md`. Run fmt, check, Clippy, targeted tests; Miri when unsafe touched.
@@ -0,0 +1,3 @@
1
+ # Rust unsafe / FFI
2
+
3
+ Minimize unsafe surface; safe wrapper owns invariant. State aliasing, alignment, initialization, lifetime, provenance, thread, unwind, and ownership assumptions beside boundary. Validate foreign pointer/length before slice; define allocator and deallocation owner; use `repr(C)` only where ABI requires. No reference from possibly null/misaligned pointer, mutable alias, unchecked integer-to-pointer guess, or unwind across FFI. Add boundary tests. Run Miri first and after fix; use sanitizer/loom when memory or concurrency model requires it.
@@ -0,0 +1,3 @@
1
+ # TypeScript
2
+
3
+ Preserve workspace runtime/package manager. Strict `tsc`; project formatter/linter/test runner. `unknown` at boundaries, then narrow or schema-parse. Prefer discriminated unions, `readonly`, `satisfies`, type-only imports, named exports. No `any`, ignored diagnostic, non-null assertion, unchecked cast, enum, empty catch, or swallowed error. Async work must expose cancellation/timeout where caller needs it. React: semantic HTML, stable keys, minimal effects; derive state instead of syncing it. Test public behavior with Vitest/project runner. Run formatter, typecheck, targeted tests.
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: refactor
3
+ description: Behavior-preserving structural change with tests and semantic navigation. Use when asked to refactor, restructure, extract, simplify, or modernize code.
4
+ ---
5
+
6
+ # Refactor
7
+
8
+ Scope one smell or seam. No feature, formatting sweep, rename drift, or cleanup bundle.
9
+
10
+ 1. Map target responsibility, callers, references, tests, public contract.
11
+ 2. State invariant that must remain true.
12
+ 3. Add or run behavior-locking test before move.
13
+ 4. Use LSP references/rename for symbols. Use AST rewrite for repeated syntax shape.
14
+ 5. Move one responsibility at time. Keep compatibility only when contract requires it.
15
+ 6. Run smallest test after each semantic move.
16
+ 7. Delete obsolete path only after all callers move.
17
+ 8. Run strict diagnostics and proportional suite.
18
+
19
+ Good split follows ownership, lifecycle, policy, or dependency boundary. Bad split creates pass-through files, one-call helpers, generic `utils`, or cycles.
20
+
21
+ Stop and reassess if public API changes, tests cannot distinguish behavior, concurrent user edits overlap, or required migration exceeds request.
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: remove-ai-slops
3
+ description: Remove AI-authored code smells while preserving behavior. Use when asked to clean generated code, remove AI slop, or simplify branch changes without feature work.
4
+ ---
5
+
6
+ # Remove AI Slops
7
+
8
+ Lock behavior first. Work only branch changes or explicit files. No broad repo cleanup.
9
+
10
+ Categories: dead wrapper/helper; redundant guard or fallback; broad catch; vague narrative comment; duplicated path; needless object annotation; variant `if` chain; oversized mixed module; repeated post-action verification; inefficient equivalent work.
11
+
12
+ For each category:
13
+
14
+ 1. Find exact instances.
15
+ 2. Add regression test when behavior lacks coverage.
16
+ 3. Confirm red where change fixes a bug; otherwise confirm behavior lock passes.
17
+ 4. Remove smallest smell set.
18
+ 5. Run targeted test and diagnostics.
19
+
20
+ Do not collapse distinct semantics, remove required compatibility, change error strings, reorder observable effects, or “simplify” security checks without proof. Finish with formatter, linter, strict types, targeted suite, and diff review.
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: rules
3
+ description: Explain or inspect HolyCodex scoped rule loading and cache. Use for rule locations, matching, injection, deduplication, limits, or cache behavior.
4
+ ---
5
+
6
+ # Rules
7
+
8
+ Automatic when plugin enabled. Static rules load on session start and user prompt. File rules load after matching edit. Post-compact clears session cache.
9
+
10
+ Sources: `CONTEXT.md`, `.holycodex/rules/**/*.md`, `.codex/rules/**/*.md`, `.github/instructions/**/*.md`, `.github/copilot-instructions.md`. Never load or reinject `AGENTS.md`.
11
+
12
+ Frontmatter: `alwaysApply: true` for static rule; `globs` string or list for path match. Body after frontmatter is injected. Native and plugin rules dedupe by normalized content hash. Per-rule cap 8,000 chars; event cap 24,000 chars.
13
+
14
+ Environment: `HOLYCODEX_RULES_DISABLED=1`, `HOLYCODEX_RULES_MAX_RULE_CHARS`, `HOLYCODEX_RULES_MAX_RESULT_CHARS`.
15
+
16
+ When debugging rules, report discovered files, parsed metadata, target path, match result, dedupe/cache result. Do not expose unrelated rule content.
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: security-research
3
+ description: Exploitability-led security audit with optional narrow research. Use for repository security reviews, threat analysis, vulnerability validation, or attack paths.
4
+ ---
5
+
6
+ # Security Research
7
+
8
+ Main agent owns scope, threat surface, dedupe, proof, severity, report. No Team Mode. At most two independent lanes when useful: `explorer` for one internal surface; `librarian` for named standards or dependency facts. No duplicate hunters, recursive delegation, reviewer loop, or full-history fork.
9
+
10
+ ## Rules
11
+
12
+ - Name target: repo, diff, path, release, or threat surface.
13
+ - Map entry points, attacker input, trust boundaries, sensitive assets, sinks, privilege transitions.
14
+ - No severity without reachable attack path.
15
+ - High or critical needs safe local PoC or decisive static proof plus concrete preconditions and impact.
16
+ - CWE classifies weakness. Severity measures exploitability and impact. Keep separate.
17
+ - Generic hardening is not finding.
18
+ - Never attack real or third-party systems. Use local fixture, toy payload, dry run, or static proof.
19
+
20
+ ## Flow
21
+
22
+ 1. Baseline: scope, branch/diff, sensitive paths, tests, constraints.
23
+ 2. Threat surface: attacker capability, controlled input, boundary, sink, asset.
24
+ 3. Candidates: title, path/function, attack path, impact, CWE candidate, evidence, safe proof idea.
25
+ 4. Deduplicate by root cause and attack path.
26
+ 5. Validate strongest candidate. Reproduce, falsify, or downgrade. Record exact command and observed output.
27
+ 6. Calibrate severity from proven preconditions, reachability, privilege, user action, scope, confidentiality, integrity, availability.
28
+ 7. Give minimum fix and public-seam regression test.
29
+
30
+ ## Report
31
+
32
+ Lead with `PASS`, `PASS WITH FINDINGS`, or `BLOCK`.
33
+
34
+ For each surviving finding: severity, title, CWE, affected path/function, attacker capability, attack path, proof, impact, minimum fix, regression check.
35
+
36
+ Also list downgraded and rejected candidates with reason. End with residual risk: untested surfaces and why.
37
+
38
+ Use CWE, OWASP WSTG/ASVS, and CVSS v4 only when relevant. Cite exact source. Do not claim precise CVSS score without scoring every metric.
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: tdd
3
+ description: Public-seam vertical red-green-refactor development. Use when the user requests test-first work, TDD, regression tests, or integration tests.
4
+ ---
5
+
6
+ # TDD
7
+
8
+ Find established seam before asking user. Ask only if materially different contracts remain.
9
+
10
+ ## Slice
11
+
12
+ 1. Pick one observable outcome.
13
+ 2. Red: test public seam. Run it. Confirm failure matches missing behavior, not setup error.
14
+ 3. Green: minimum production code. No second case yet.
15
+ 4. Refactor only with green test.
16
+ 5. Repeat vertical slice.
17
+
18
+ Given/When/Then: known fixture; one action; only observable result caused by action.
19
+
20
+ Reject private-method tests, tautology, snapshot abuse, broad mocking, sleeps, wall-clock dependence, implementation-coupled assertions, deleted failing tests.
21
+
22
+ Test doubles order: real object; in-memory fake; test container or sandbox; wire fake; narrow mock last. Fake must honor real contract.
23
+
24
+ Fixtures deterministic and isolated. Coverage proportional to risk. Run smallest test during loop; broader gates at completion. See `tests.md` and `mocking.md` only when needed.
@@ -0,0 +1,60 @@
1
+ # When to Mock
2
+
3
+ Mock at **system boundaries** only:
4
+
5
+ - External APIs (payment, email, etc.)
6
+ - Databases (sometimes - prefer test DB)
7
+ - Time/randomness
8
+ - File system (sometimes)
9
+
10
+ Don't mock:
11
+
12
+ - Your own classes/modules
13
+ - Internal collaborators
14
+ - Anything you control
15
+
16
+ ## Designing for Mockability
17
+
18
+ At system boundaries, design interfaces that are easy to mock:
19
+
20
+ **1. Use dependency injection**
21
+
22
+ Pass external dependencies in rather than creating them internally:
23
+
24
+ ```typescript
25
+ // Easy to mock
26
+ function processPayment(order, paymentClient) {
27
+ return paymentClient.charge(order.total);
28
+ }
29
+
30
+ // Hard to mock
31
+ function processPayment(order) {
32
+ const client = new StripeClient(process.env.STRIPE_KEY);
33
+ return client.charge(order.total);
34
+ }
35
+ ```
36
+
37
+ **2. Prefer SDK-style interfaces over generic fetchers**
38
+
39
+ Create specific functions for each external operation instead of one generic function with conditional logic:
40
+
41
+ ```typescript
42
+ // GOOD: Each function is independently mockable
43
+ const api = {
44
+ getUser: (id) => fetch(`/users/${id}`),
45
+ getOrders: (userId) => fetch(`/users/${userId}/orders`),
46
+ createOrder: (data) => fetch("/orders", { method: "POST", body: data }),
47
+ };
48
+
49
+ // BAD: Mocking requires conditional logic inside the mock
50
+ const api = {
51
+ fetch: (endpoint, options) => fetch(endpoint, options),
52
+ };
53
+ ```
54
+
55
+ The SDK approach means:
56
+
57
+ - Each mock returns one specific shape
58
+ - No conditional logic in test setup
59
+ - Easier to see which endpoints a test exercises
60
+ - Type safety per endpoint
@@ -0,0 +1,77 @@
1
+ # Good and Bad Tests
2
+
3
+ ## Good Tests
4
+
5
+ **Integration-style**: Test through real interfaces, not mocks of internal parts.
6
+
7
+ ```typescript
8
+ // GOOD: Tests observable behavior
9
+ test("user can checkout with valid cart", async () => {
10
+ const cart = createCart();
11
+ cart.add(product);
12
+ const result = await checkout(cart, paymentMethod);
13
+ expect(result.status).toBe("confirmed");
14
+ });
15
+ ```
16
+
17
+ Characteristics:
18
+
19
+ - Tests behavior users/callers care about
20
+ - Uses public API only
21
+ - Survives internal refactors
22
+ - Describes WHAT, not HOW
23
+ - One logical assertion per test
24
+
25
+ ## Bad Tests
26
+
27
+ **Implementation-detail tests**: Coupled to internal structure.
28
+
29
+ ```typescript
30
+ // BAD: Tests implementation details
31
+ test("checkout calls paymentService.process", async () => {
32
+ const mockPayment = jest.mock(paymentService);
33
+ await checkout(cart, payment);
34
+ expect(mockPayment.process).toHaveBeenCalledWith(cart.total);
35
+ });
36
+ ```
37
+
38
+ Red flags:
39
+
40
+ - Mocking internal collaborators
41
+ - Testing private methods
42
+ - Asserting on call counts/order
43
+ - Test breaks when refactoring without behavior change
44
+ - Test name describes HOW not WHAT
45
+ - Verifying through external means instead of interface
46
+
47
+ ```typescript
48
+ // BAD: Bypasses interface to verify
49
+ test("createUser saves to database", async () => {
50
+ await createUser({ name: "Alice" });
51
+ const row = await db.query("SELECT * FROM users WHERE name = ?", ["Alice"]);
52
+ expect(row).toBeDefined();
53
+ });
54
+
55
+ // GOOD: Verifies through interface
56
+ test("createUser makes user retrievable", async () => {
57
+ const user = await createUser({ name: "Alice" });
58
+ const retrieved = await getUser(user.id);
59
+ expect(retrieved.name).toBe("Alice");
60
+ });
61
+ ```
62
+
63
+ **Tautological tests**: Expected value restates the implementation, so the test passes by construction.
64
+
65
+ ```typescript
66
+ // BAD: Expected value is recomputed the way the code computes it
67
+ test("calculateTotal sums line items", () => {
68
+ const items = [{ price: 10 }, { price: 5 }];
69
+ const expected = items.reduce((sum, i) => sum + i.price, 0);
70
+ expect(calculateTotal(items)).toBe(expected);
71
+ });
72
+
73
+ // GOOD: Expected value is an independent, known literal
74
+ test("calculateTotal sums line items", () => {
75
+ expect(calculateTotal([{ price: 10 }, { price: 5 }])).toBe(15);
76
+ });
77
+ ```