Skip to content
Back to skills

Lint

ASecurity

Run harness, privacy, structural, and staleness checks.

  • 4 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 9, 2026
ai-agentspythonrustgobashgit

Security analysis

A100/100

Scanned October 9, 2026

npx -y skills add mhxie/Atelier --skill lint --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Lint?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Lint
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mhxie-lint-atelier/badge)](https://www.skillsdirectory.com/skills/mhxie-lint-atelier)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: lint
description: Run harness, privacy, structural, and staleness checks.
---
# /lint — Structural + corpus-level checks over `<paths.wiki>/`

> Also reachable via `/hi <natural language>` (e.g., `/hi lint the wiki`, `/hi wiki audit`,
> `/hi wiki orphans`). See `harness/intents.toml` `[intents.lint]` for the row's example
> phrases. Both paths execute this same procedure.

Deterministic Python pass. The LLM never hand-checks structure — `scripts/lint.py` is the single source of truth, mirroring the `scripts/trust.py` pattern.

**Scope:** Three passes. (0) Harness portability, $OV ingestion hygiene, and privacy checks. (1) Structural: everything under `<paths.wiki>/`. (2) Staleness: L2 working-layer directories (`<paths.agent_findings>/`, `<paths.wip>/`, `<paths.gtd>/`, `<paths.preprints>/`, `<paths.reflections>/`, `<paths.research>/`). Structural lint enforces the wiki schema; staleness lint surfaces L2 notes that need attention (archival, compaction, or promotion to L4).

**What gets checked:**

| Check | Severity | Source |
|---|---|---|
| Per-note parse errors: schema items 1-10, malformed citation metadata, or dangling targets (`parse-error`) | ERROR | `scripts/trust.py` parser + resolver |
| Disputed claim or fully expired evidence (`claim-attention`) | WARN | `scripts/wiki_review.py`; reasons are in `autoevo-applied-*` receipts. Route to the user. |
| Duplicate titles across wiki entries (breaks citation resolution) | ERROR | `scripts/lint.py` |
| Slug ↔ title alignment (filename stem matches H1 title) | WARN | `scripts/lint.py` |
| Orphan entry: no inbound citation from another wiki entry | WARN | `scripts/lint.py` graph topology |
| No outbound citation to another wiki entry | INFO | `scripts/lint.py` graph topology |
| Shared anchor without a citation edge between entries | INFO | `scripts/lint.py` graph topology |
| `url:` or `gist:` anchor missing `readwise:` field (`readwise-missing`) | WARN | `scripts/lint.py` — save to Readwise with `anchor-evidence` tag and backfill the document ID; fix via `uv run scripts/snapshot_anchors.py --apply --note "<paths.wiki>/<Title>.md"` |
| Technical term in claim body not in vocabulary allowlist and not matching any wiki entry title (`unfounded-term`) | INFO | `scripts/lint.py` — add term to `scripts/wiki_vocabulary.txt` if common knowledge, or add a wiki entry, or add a parenthetical definition inline |
| Localized shadow missing for a configured language (`shadow-missing`) | WARN | `scripts/lint.py` — run /promote Phase 4 or regenerate the shadow manually. |
| Localized shadow older than English source (`shadow-stale`) | WARN | `scripts/lint.py` — re-translate the localized shadow to match the updated English source |
| Public configuration schema and Claude/Codex harness alignment (`registry-schema`, `registry-read`, `registry-validator`, source/reference/edge findings) | ERROR/WARN/INFO | `harness/registry.schema.json` + `scripts/harness_lint.py` |
| `$OV` ingestion hygiene (missing READMEs, raw-without-digest, archive↔working-tier overlap, root-level orphans, empty .md files, suspicious top-level dirs, vault layout, duplicate Reflect titles) | INFO (advisory) | `scripts/zk_audit.py` — see `protocols/drive-zk-ingestion.md` § Post-ingestion verification |

**Not checked:** cross-note `@anchor` date consistency. Per `protocols/wiki-schema.md`, `valid_at` is the day the marker was added to its home note, so the same source being anchored from two notes on different days is the normal case.

Exit code: 0 if no ERROR-level findings, 1 otherwise. WARN and INFO never fail the run.

## Process

### Phase 0: Harness health

```
Bash: python3 scripts/harness_lint.py --json
```

Read `counts` and `findings` (`severity`, `code`, `where`, `message`). Any ERROR
blocks the run until fixed; WARN and INFO are advisory. This pass owns the
AGENTS.md size and bold-marker checks; do not repeat them manually.

`registry-schema` identifies the source file and failing field. A
`registry-validator` setup error requires installing the pinned dependencies
with `uv sync --locked` before retrying; lint itself never installs them.

### Phase 0b: $OV ingestion hygiene audit

```
Bash: uv run scripts/zk_audit.py --json
```

Read `categories` and `total`; category rows identify `where` and `detail`.

Advisory only: never blocks the run. Exit code 0 unless $OV is missing (exit 2). Surface a one-line summary per non-empty category. Detailed listings are read on demand via `uv run scripts/zk_audit.py` (no `--json`). Source of truth: `protocols/drive-zk-ingestion.md` § Post-ingestion verification.

### Phase 0c: Privacy leak scan

```
Bash: uv run scripts/privacy_check.py --json
```

`--json` mode emits a document on every run regardless of exit code. Route on its `action` field: `"proceed"` → pass (WARN first on any `coverage_warnings`); `"soft_skip"` → note "privacy gate skipped (<reason>)" and continue; `"abort"` → ERROR, block and present each `hits` entry verbatim. No JSON / exit ≥ 2 without JSON → real script error: surface stderr, soft-skip.

Any non-empty `hits` array is an ERROR: each entry is a private identifier (filename stem, wikilink target, slug from `profile/private_slugs.txt`, or exact term from `profile/private_terms.txt`) that appears in a public-bound pathname, worktree file, or staged blob. Present each hit verbatim with its file, source, and line number. Remediation:

- Replace the private title with a generic placeholder (e.g., `Sample Wiki Entry`, `Topic A`).
- Add private names, places, program labels, and preference phrases that cannot be inferred from vault titles to gitignored `profile/private_terms.txt`, one exact term per line.
- Or, if the exposure is deliberate (e.g., the title is fully public and appears as an illustrative example), add the stem to `scripts/privacy_allowlist.txt` and document the rationale in the commit message.

The check is a blocking quality gate for any commit that touches tracked files when the gate ran meaningfully (no skip flag). Do not proceed to structural lint if Phase 0c returns hits.
An absent exact-term sidecar is a coverage warning, not proof of a leak. Keep the
semantic privacy round enabled and populate the gitignored sidecar before
claiming exact identity or preference coverage.

### Phase 1a: Structural lint

```
Bash: uv run scripts/lint.py --json
```

Read `wiki_dir`, `counts`, and `findings` using the Phase 0 finding fields.

### Phase 1b: Staleness lint

```
Bash: python3 scripts/staleness.py --json
```

Read `thresholds`, `counts`, and `notes` (`path`, `staleness`, `category`).

Staleness findings are always advisory (no ERROR level). They surface L2 notes that have gone cold, using the formula `days_since_modified / (1 + log(1 + reference_count))`. Notes referenced from wiki entries or recent reflections decay slower.

### Phase 2: Present

Group findings by severity. If the corpus is clean, say so and stop.

For each ERROR-level finding: show the code, file path, and message verbatim. Do not rephrase the message — `scripts/trust.py` and `scripts/lint.py` emit precise line numbers that the user needs.

For WARN-level findings: show them but mark them as non-blocking.

Summarize INFO findings (e.g., "4 entries lack outbound citations") unless the user asks for the full list.

**Staleness section** (from Phase 1b): present after the structural findings, under a separate heading. Group by category:
- **stale** notes: list paths, suggest archiving to `<paths.archive>/`
- **dormant** notes: list paths, suggest review or compaction
- **promote** candidates: list paths, suggest `/promote` to create L4 wiki entries
- If all notes are active, say so in one line and move on.

### Phase 3: Offer fixes

For each fixable category, ask the user before acting:

| Finding code | Fix | How |
|---|---|---|
| `slug-mismatch` | Rename file or edit H1 | Ask the user which side to change. Never rename without confirmation — downstream `@cite` targets key off the title. |
| `parse-error` (e.g., missing `valid_at`, duplicate claim IDs, invalid ranges or dangling citations) | Edit the wiki entry | Route to the user; do not auto-edit wiki entries. |
| `duplicate-title` | Edit one of the H1 titles | Ask the user which note keeps the title. |
| `orphan-entry` | Add inline citation references inside related claims | Suggest supported claim links using `protocols/wiki-schema.md`; shared-anchor findings can identify candidates. |
| `shared-anchor-no-cite` | Add a supported citation reference | Show the shared anchor and propose the citing claim and target. A shared source alone does not establish dependence. |

### Phase 4: Rerun (if fixes applied)

If any user-driven fixes were made, suggest rerunning `/lint` manually to confirm the state.

## Rules

1. **Never hand-check structure.** Always call `scripts/lint.py`. If the script is missing or errors, fix the script — do not re-derive the checks in the LLM.
2. **Ask before fixing.** All fixes route back to the user; `scripts/lint.py` is advisory-only.
3. **ERROR findings block further wiki work.** If a wiki entry has a parse error, do not cite it from new entries, do not score it — fix it first.
4. **WARN findings are advisory.** The system keeps working; the user decides whether to act.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.