Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/agent-setup-playbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,20 @@ Skip it when:

If `.audit/` artifacts may be created, make sure `.audit/` is ignored before running the tool.

When Lumin Repo Lens is approved and available, use it as an evidence workflow, not as a magic reviewer:

- No structural claim without evidence: cite a produced artifact, a direct file inspection, or both before claiming a duplicate helper, public surface, cycle, fan-in hotspot, re-export drift, or missing boundary.
- No absence claim without scan range: say "not observed in this scan range" instead of "does not exist" unless the checked range, files, and exclusions make that claim true.
- For a first pass or branch-level review, prefer the upstream full audit workflow. Treat `quick, full, ci` as audit cadences with different confidence, and read the produced `manifest.json` before using summaries.
- Before writing code, capture the pre-write intent with these keys: `names, shapes, files, dependencies, plannedTypeEscapes`. The agent should infer this from the user's task and repository evidence; the user should not need to hand-write JSON.
- Read the invocation-specific advisory produced for that pre-write run before editing. Do not rely only on a `latest` pointer when a command produced a more specific advisory path.
- After writing, run the matching post-write delta against the same invocation-specific advisory. Review `silent-new` type escapes, planned-not-observed type escapes, unexpected files outside the intent, scan range changes, and degraded confidence.
- Use canon draft or check-canon only for Lumin-supported canon sources.
- Lumin canon sources are limited to type ownership, helper registry, topology, and naming.
- Use living audit or project docs for boundary policy, public API policy, dependency direction, and re-export policy.
- Keep a living audit when a repo needs ongoing structural tracking. Prefer a shareable repository doc such as `docs/current/audit/lumin-structural-audit.md` when it is safe to commit; otherwise keep the same index shape in an `Obsidian or private wiki` page.
- Do not treat Lumin warnings as automatic refactor permission. The agent still needs to inspect cited files, avoid false-positive cleanup, and make the smallest change approved by the task.

### Dependency, Type, Cycle, And Complexity Checks

Dependency lint, strict type checks, cycle detection, complexity limits, and file/function size limits are strong controls, but they are tooling changes.
Expand Down
17 changes: 17 additions & 0 deletions docs/local-project-knowledge-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,23 @@ Copy this template into a project-local `local.md`, an untracked note, or an Obs
- Storage or persistence:
- UI or delivery surfaces:

## Structural Evidence Index

- Last refreshed:
- Scan range:
- Claim rule: state scan range before saying something was not found.
- Confidence or blind spots:
- `.audit/manifest.json`:
- `.audit/audit-summary.latest.md`:
- `.audit/pre-write-advisory.latest.json`:
- `.audit/post-write-delta.latest.json`:
- `docs/current/audit/lumin-structural-audit.md`:
- Canon or source-of-truth docs:
- Files that must be inspected before touching shared helpers:
- Files that must be inspected before changing public APIs:
- Files that must be inspected before changing import topology:
- Local-only notes that should stay untracked:

## Source Of Truth

- Shared utility source of truth:
Expand Down
49 changes: 49 additions & 0 deletions docs/vibe-coding-guardrails.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,55 @@ LUMIN_REPO_LENS_NO_AUTO_INSTALL=1 node skills/lumin-repo-lens/scripts/audit-repo

The tool output is evidence. The agent must still inspect the cited files and make the engineering call.

## Lumin Evidence Lifecycle

Use this lifecycle only when the target repository is TS/JS-heavy and Lumin Repo Lens is installed or explicitly approved. If Lumin is missing, the agent should still follow the same evidence rules with native repo tools and direct inspection.

### Structural claim contract

The contract is stricter than "run a tool and summarize it":

- No structural claim without evidence. A claim about duplicate helpers, hidden coupling, dead exports, cycles, topology, barrel drift, public-surface risk, god files, or fan-in/fan-out hotspots needs a cited artifact or direct file evidence.
- No absence claim without scan range. `not observed is not does not exist`; report the files, directories, excludes, language coverage, and confidence behind the statement.
- Read `.audit/manifest.json` first when it exists. It is the source for scan range, produced artifacts, skipped lanes, confidence, and blind spots.
- Treat `.audit/audit-summary.latest.md` as an artifact map, not a final review. The engineering review still belongs to the agent.
- Label structural conclusions as `grounded, degraded, unknown` when artifact quality, parse coverage, or scan range changes affect confidence.
- Avoid false-positive cleanup. Static "no consumer found" evidence is not enough to delete code when resolver blindness, parse taint, runtime imports, framework conventions, generated files, or public API promises might apply.

### Audit cadence

Use the smallest cadence that gives enough evidence:

- `quick, full, ci`: quick is for focused checks, full is for first pass or branch-level reviews, and ci is for automated guardrail enforcement when the repo has opted in.
- Use full evidence for a first checkup, large refactor, post-refactor review, stale artifacts, or an explicit structural audit request.
- Use focused checks for a narrow feature after a recent comparable full audit.
- Do not compare two audit results unless their scan range and confidence are compatible enough for the claim being made.

### Pre-write and post-write

For a scoped code task:

1. Build the pre-write intent from the requested change. Track `names`, `shapes`, `files`, `dependencies`, and `plannedTypeEscapes`.
2. Run the approved Lumin pre-write flow or native equivalent.
3. Read the invocation-specific `pre-write-advisory` before editing. Do not rely only on a `latest` pointer when a specific advisory path exists.
4. Implement with TDD and the write gate in this guide.
5. Run the matching `post-write-delta` against the same advisory.
6. Lumin post-write machine evidence covers `silent-new` type escapes, planned-not-observed type escapes, unexpected new files outside the intent, scan range changes, and degraded confidence.

If the post-write delta says a change was not observed, inspect the actual diff and the scan range before concluding anything. The correct closeout may be "unknown until a wider audit runs."

Manual post-write review still covers duplicate helpers, changed dependencies, public API drift, dependency direction, re-export drift, hidden coupling, and weak tests. Keep those as engineering review claims backed by direct file evidence or repository-native tools, not as unsupported Lumin delta fields.

### Canon and living audit

Use canon or living audit docs when the repo has enough structure to justify durable memory:

- Lumin canon sources are limited to type ownership, helper registry, topology, and naming.
- Use living audit or project docs for boundary policy, public API policy, dependency direction, and re-export policy.
- Keep a living audit for unresolved structure risks, stale evidence, recurring hotspots, and accepted deviations.
- Prefer `docs/current/audit/lumin-structural-audit.md` for shareable project facts.
- Keep private local details in `local.md`, an untracked note, or an Obsidian page. The repository should link to the kind of knowledge needed, not to Hun's personal vault path.

## Local Wiki Or Obsidian Index

Use `docs/local-project-knowledge-template.md` as the shape of a project wiki page.
Expand Down
10 changes: 10 additions & 0 deletions prompts/apply-vibe-coding-guardrails.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,28 @@ Before changing files:
- inspect existing docs, tests, lint, type checks, and dependency tooling
- identify module boundaries, existing helpers, types, shapes, public APIs, re-exports, and error boundaries
- inventory optional tools that may matter for this repo, including Obsidian, Lumin Repo Lens, dependency lint, strict type checks, cycle detection, and complexity limits
- if Lumin Repo Lens is installed or approved for a TS/JS repo, read .audit/manifest.json first when it exists and treat scan range, skipped lanes, and confidence as part of every structural claim
- do not claim that a helper, shape, public API, cycle, or consumer does not exist unless you state the scan range; say "not observed in this scan range" when the evidence is partial
- do not invent tool commands, config options, package names, or API details

Set up only the smallest useful guardrails for this repository:
- add .audit/ to .gitignore if local evidence artifacts may be created
- add or update local project knowledge guidance without committing private paths
- document the pre-write lens, write gate, and post-write review loop for this repo
- include a structural evidence index that points to shareable audit docs, .audit artifact names, source-of-truth docs, and any private wiki or Obsidian page type without committing personal vault paths
- keep optional tools such as Lumin Repo Lens optional unless this repo already uses TS/JS and I explicitly approve installing it
- for Obsidian or any other optional desktop app, plugin, CLI, browser extension, or package dependency, explain whether it is required, recommended, optional, or skipped
- ask before installing optional tools; do not install them only because a guide mentions them
- on macOS, verify the package name or official source before installing; on Windows PowerShell, use commands such as winget search Obsidian to verify the package name before installation
- do not commit personal vault paths, credentials, tokens, MCP endpoints, auth state, or machine-specific trust settings

When documenting the daily workflow:
- make pre-write intent explicit with names, shapes, files, dependencies, and plannedTypeEscapes
- require the agent to read the invocation-specific pre-write advisory before editing when one is produced
- require post-write delta review against the same advisory after editing
- check Lumin machine evidence for `silent-new` type escapes, planned-not-observed type escapes, unexpected new files, and degraded scan confidence
- check duplicate helpers, changed dependencies, public API drift, and re-export drift as manual post-write review claims backed by direct evidence

Use TDD for any behavior changes. Tests must cover edge cases, failure paths, and side effects. Mocks belong at external boundaries only; do not mock internal implementation details.

After setup:
Expand Down
6 changes: 6 additions & 0 deletions prompts/start-with-vibe-coding-guardrails.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ Before implementation, run a pre-write lens:
- search for existing helpers, types, shapes, public APIs, and tests before creating new ones
- identify edge cases, failure paths, side effects, and concurrency risks
- check whether .audit/ or other local evidence artifacts should remain untracked
- if Lumin Repo Lens or a comparable structure tool is available, read the current manifest or scan summary before making structural claims
- state the scan range before saying something was not found
- capture pre-write intent as names, shapes, files, dependencies, and plannedTypeEscapes
- read the invocation-specific pre-write advisory when one is produced

Use TDD:
- write the failing test first
Expand All @@ -29,6 +33,8 @@ During implementation:

After implementation, run post-write review:
- check for duplicate helpers, duplicate shapes, dead code, commented-out code, hidden coupling, initialization order dependencies, global state, unmanaged re-exports, fan-in/fan-out hotspots, and weak tests
- compare the diff against the pre-write advisory or local evidence index, and check Lumin machine evidence for `silent-new` type escapes, planned-not-observed type escapes, unexpected new files, and degraded scan confidence
- keep duplicate helpers, dependency drift, public API drift, and re-export drift as manual review claims backed by direct evidence
- run the repository's real verification commands
- report exact commands, results, files changed, and remaining risks
```
9 changes: 9 additions & 0 deletions scripts/inventory_optional_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,15 @@ def classify_lumin_repo_lens(
detected = True
evidence.append("lumin-repo-lens command is on PATH")
evidence.append("Target repository appears TS/JS-heavy" if ts_js else "No TS/JS repository signal detected")
for artifact_name in (
"manifest.json",
"audit-summary.latest.md",
"pre-write-advisory.latest.json",
"post-write-delta.latest.json",
):
artifact_path = repo_root / ".audit" / artifact_name
if artifact_path.exists():
evidence.append(f".audit/{artifact_name} exists")

return ToolInventory(
name="lumin-repo-lens",
Expand Down
28 changes: 28 additions & 0 deletions tests/test_optional_tool_inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,34 @@ def test_json_output_reports_required_decision_fields(self) -> None:
self.assertIn("reason", first)
self.assertIn("install_status", first)

def test_lumin_inventory_reports_existing_audit_artifacts(self) -> None:
with tempfile.TemporaryDirectory() as tmpdir:
repo_root = Path(tmpdir)
audit_dir = repo_root / ".audit"
audit_dir.mkdir()
(audit_dir / "manifest.json").write_text("{}", encoding="utf-8")
(audit_dir / "audit-summary.latest.md").write_text("# audit\n", encoding="utf-8")
(audit_dir / "pre-write-advisory.latest.json").write_text(
"{}", encoding="utf-8"
)
(audit_dir / "post-write-delta.latest.json").write_text(
"{}", encoding="utf-8"
)
(repo_root / "package.json").write_text("{}", encoding="utf-8")

results = inventory_optional_tools.build_inventory(
repo_root,
command_lookup=lambda command: None,
path_exists=lambda path: False,
platform_name="Linux",
)
lumin = next(result for result in results if result.name == "lumin-repo-lens")

self.assertIn(".audit/manifest.json exists", lumin.evidence)
self.assertIn(".audit/audit-summary.latest.md exists", lumin.evidence)
self.assertIn(".audit/pre-write-advisory.latest.json exists", lumin.evidence)
self.assertIn(".audit/post-write-delta.latest.json exists", lumin.evidence)


if __name__ == "__main__":
unittest.main()
107 changes: 107 additions & 0 deletions tests/test_vibe_coding_guardrails.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,113 @@ def test_playbook_points_agents_at_optional_tool_inventory_script(self) -> None:
for phrase in expected_phrases:
self.assertIn(phrase, playbook)

def test_playbook_covers_lumin_evidence_backed_workflow(self) -> None:
playbook = (REPO_ROOT / "docs" / "agent-setup-playbook.md").read_text(
encoding="utf-8"
)

expected_phrases = (
"No structural claim without evidence",
"No absence claim without scan range",
"pre-write intent",
"names, shapes, files, dependencies, plannedTypeEscapes",
"invocation-specific advisory",
"post-write delta",
"silent-new",
"canon draft",
"living audit",
"docs/current/audit/lumin-structural-audit.md",
"Obsidian or private wiki",
)
for phrase in expected_phrases:
self.assertIn(phrase, playbook)

def test_vibe_coding_guide_covers_lumin_structural_claim_contract(self) -> None:
guide = (REPO_ROOT / "docs" / "vibe-coding-guardrails.md").read_text(
encoding="utf-8"
)

expected_phrases = (
"Lumin Evidence Lifecycle",
"quick, full, ci",
"manifest.json",
"audit-summary.latest.md",
"grounded, degraded, unknown",
"not observed is not does not exist",
"scan range",
"false-positive",
"pre-write-advisory",
"post-write-delta",
)
for phrase in expected_phrases:
self.assertIn(phrase, guide)

def test_lumin_docs_do_not_overclaim_machine_post_write_outputs(self) -> None:
checked_paths = (
REPO_ROOT / "docs" / "agent-setup-playbook.md",
REPO_ROOT / "docs" / "vibe-coding-guardrails.md",
REPO_ROOT / "prompts" / "apply-vibe-coding-guardrails.md",
REPO_ROOT / "prompts" / "start-with-vibe-coding-guardrails.md",
)

for path in checked_paths:
with self.subTest(path=path.name):
content = path.read_text(encoding="utf-8")
self.assertNotIn("silent-new helpers", content)

guide = (REPO_ROOT / "docs" / "vibe-coding-guardrails.md").read_text(
encoding="utf-8"
)
lifecycle = guide.split("## Lumin Evidence Lifecycle", maxsplit=1)[1].split(
"## Local Wiki Or Obsidian Index",
maxsplit=1,
)[0]

self.assertIn(
"Lumin post-write machine evidence covers `silent-new` type escapes",
lifecycle,
)
self.assertIn(
"Manual post-write review still covers duplicate helpers",
lifecycle,
)
self.assertNotIn("changed dependencies, and degraded scan confidence", lifecycle)

def test_lumin_canon_sources_are_limited_to_upstream_sources(self) -> None:
guide = (REPO_ROOT / "docs" / "vibe-coding-guardrails.md").read_text(
encoding="utf-8"
)
playbook = (REPO_ROOT / "docs" / "agent-setup-playbook.md").read_text(
encoding="utf-8"
)

expected_phrases = (
"Lumin canon sources are limited to type ownership, helper registry, topology, and naming.",
"Use living audit or project docs for boundary policy, public API policy, dependency direction, and re-export policy.",
)
for phrase in expected_phrases:
self.assertIn(phrase, guide)
self.assertIn(phrase, playbook)

def test_local_project_knowledge_template_indexes_structural_evidence(self) -> None:
template = (REPO_ROOT / "docs" / "local-project-knowledge-template.md").read_text(
encoding="utf-8"
)

expected_phrases = (
"Structural Evidence Index",
".audit/manifest.json",
".audit/audit-summary.latest.md",
".audit/pre-write-advisory",
".audit/post-write-delta",
"docs/current/audit/lumin-structural-audit.md",
"Canon or source-of-truth docs",
"scan range",
"Last refreshed",
)
for phrase in expected_phrases:
self.assertIn(phrase, template)

def test_vibe_coding_guide_maps_original_problem_checklist_to_repo_artifacts(self) -> None:
guide = (REPO_ROOT / "docs" / "vibe-coding-guardrails.md").read_text(
encoding="utf-8"
Expand Down
Loading