Skills Architecture
Six description-routed Skills, eight reference Files mounted at session creation, seventy markdown files of operator-voice research substrate.
Vernacular note. Throughout this page, "M13" refers to the Day-5 hackathon milestone (2026-04-25) that retired the flat
bl-skillsread_only memory store and moved skill content onto the Anthropic Skills primitive plus a set of mounted reference Files. "Path C" is the shipped delivery shape that resulted (versus Path A, the retired memstore approach, and Path B, a callable-agents hunter pattern that was deferred). The full glossary is on the docs index and the timeline view is on the Build Timeline page.
Why skills, not prompts
A naive design would shove the operator-knowledge directly into the curator's system prompt. That would:
- Blow the prompt budget. ModSec grammar alone is ~8 KB of operator-voice prose; six operator behaviors are five times that.
- Make every session creation expensive, re-uploading the same content on every wake.
- Couple knowledge to deploy cadence. New domain knowledge would require a
blrelease.
blacklight splits the work across two of the four Anthropic Managed Agents primitives that carry skill content. Routing Skills carry operator-voice behaviors, description-routed, lazy-loaded only when the description matches the current reasoning need. Reference Files carry substrate context, always present at session create, mounted under /skills/<basename>. (The other two primitives, Memory Store and Sessions, carry case state and the curator session itself; see the Path C primitives map.) Adding a new domain is a matter of dropping a file and running bl setup --sync. Zero Runner code change. Zero agent retraining.
Layered shape
Three repo subtrees, three primitives, three lifecycles.
Layer 1 · routing-skills/ · 6 platform Skills
Description-routed, lazy-loaded by the Anthropic Skills primitive when the description matches the turn. Each routing Skill is a <name>/{description.txt, SKILL.md} pair. description.txt is the routing description the platform matches on; SKILL.md is the body that gets lazy-loaded into the curator's context when routed.
synthesizing-evidence/prescribing-defensive-payloads/curating-cases/gating-false-positives/extracting-iocs/authoring-incident-briefs/
Layer 2 · skills-corpus/ · 8 mounted at session create
Workspace Files; always present, not lazy-loaded; mounted at /skills/<basename>.
foundations.mdsubstrate-context-corpus.mdsynthesizing-evidence-corpus.mdprescribing-defensive-payloads-corpus.mdcurating-cases-corpus.mdgating-false-positives-corpus.mdextracting-iocs-corpus.mdauthoring-incident-briefs-corpus.md
Layer 3 · skills/ · 70 .md / 23 dirs · raw research
Read-on-GitHub source the reference files are distilled from; not loaded at runtime.
actor-attribution/, agentic-minutes-playbook/, apf-grammar/, apsb25-94/, bl-capabilities/, cpanel-easyapache/, defense-synthesis/, false-positives/, hosting-stack/, ic-brief-format/, ioc-aggregation/, ir-playbook/, legacy-os-pitfalls/, linux-forensics/, lmd-triggers/, magento-attacks/, modsec-grammar/, obfuscation/, remediation/, ride-the-substrate/, shared-hosting-attack-shapes/, timeline/, webshell-families/.
Path C: what changed in M13
Before M13, blacklight ran a flat bl-skills read_only memory store with ~22 operator-voice markdown files at ≤50 KB total. That memstore is retired. Skill content now lives in the Skills primitive (description-routed, lazy-loaded) instead of a flat read_only memstore. Routing Skills version-pinning at session creation preserves the same "skills can't be rewritten by attacker-controlled log content" invariant under Path C.
Older docs (and earlier versions of this page) named the bl-skills memstore. They predate this change. The retirement note in Architecture §3.4 is the canonical pointer.
Workspace-allowlist fallback
The Skills primitive (POST /v1/skills) is gated to allowlisted workspaces. blacklight's curator workspace is not on the allowlist as of v0.6.0 (see Anthropic API Notes §2).
bl_setup_seed_skills probes /v1/skills with raw curl: HTTP 200 → create / version-bump per routing-skills/<name>/; HTTP 404 → fallback to bl_setup_seed_skills_as_files, which uploads each SKILL.md as a reference File at /skills/<name>-skill.md. The curator system prompt names the reference-file paths explicitly. The fallback loses platform-side description routing — the curator picks from a static reference set instead — but it still ships on a non-allowlisted workspace.
Authoring discipline
Each operator-voice file follows five rules:
- Open with a scenario from lived experience, the incident, the shift boundary, the customer call. Not a definition.
- State a non-obvious rule, something a competent analyst who has not worked at this scale would get wrong.
- Give a concrete example drawn from public APSB25-94 material (or other public sources). Never operator-local data.
- Name a failure mode and how the rule handles it. What goes wrong if you ignore the rule. What the rule prevents.
- Assume operator literacy. Do not explain generic concepts. The reader runs production hosts; they know what a webshell is, what an IP block does, what
crontab -llists.
If the only available draft would be generic IR/SOC boilerplate, flag the gap and land the file later, never ship slop.
This is the discipline that keeps the curator's reasoning sharp. A skill bundle padded with generic content makes the curator hallucinate generic answers.
Third-party extensibility
A defender running DirectAdmin, Virtualmin, Plesk drops their own subtree under skills/<platform>/ with a description.txt + SKILL.md and runs bl setup --sync. SHA-256 delta-check picks up the additions; the curator reads them on next session wake. New vocabulary available; zero Runner code change; zero agent retraining.
External skill directories (--skill-dir <path> for a tree outside the repo) are roadmap item 10.
Six routing Skills
| Slug | Pitch |
|---|---|
synthesizing-evidence | Cross-stream correlation discipline. HIGH/MEDIUM confidence requires citations from at least two evidence streams, the rule that anchors hallucination resistance. |
prescribing-defensive-payloads | ModSec rule bodies, firewall entries, scanner signatures, authored to survive ops review. Pre-flight gates inside the curator sandbox before promotion. |
curating-cases | Case lifecycle: hypothesis revision, kill-chain reconstruction, open-question tracking, close gates. |
gating-false-positives | FP discipline before signatures ship. Backup-artifact patterns, vendor allowlists, the deterministic baseline + Haiku 4.5 adjudication path. |
extracting-iocs | IP clustering, URL evasion → generalized regex, file-pattern → YARA synthesis. |
authoring-incident-briefs | Severity vocabulary, brief shape, the artifact bl case close renders. |
Eight reference Files
| File | Note |
|---|---|
foundations.md | Cross-skill anchors (untrusted-content fence taxonomy, evidence pre-parse contract, model routing). Read every turn. |
substrate-context-corpus.md | cPanel / EasyApache / shared-hosting layout. The "where do logs live, how is mod_security packaged" map. |
synthesizing-evidence-corpus.md | Cross-stream correlation worked examples. |
prescribing-defensive-payloads-corpus.md | ModSec / APF / CSF / iptables / nftables grammar with public worked rules. |
curating-cases-corpus.md | Case lifecycle worked examples, APSB25-94 polyshell, SessionReaper-class persistence. |
gating-false-positives-corpus.md | FP backup-artifact + vendor-tree patterns the gate trips on. |
extracting-iocs-corpus.md | IOC aggregation cookbook, clustering, generalization, dedup. |
authoring-incident-briefs-corpus.md | Brief template + severity vocab + worked closes. |
Skills sync delta-detection
bl setup --sync SHA-256-diffs each routing-skills/<name>/{description.txt,SKILL.md} and skills-corpus/*.md against state.json's agent.skill_versions and files.<slug>.content_sha256. Changed files are pushed; old file_ids are queued in state.files_pending_deletion[] for --gc. Operator running bl setup --sync on host 5 after host 1 produces a no-op with a friendly summary. Detail in Setup Flow.