Built with Claude Code
Provenance. The honest version.
blacklight is the agentic-defense entry in R-fx Networks' OSS portfolio, written end-to-end during the Anthropic / Cerebral Valley "Built with 4.7" April 2026 hackathon. The submission window opened at the first commit on this repo and closes at 8 PM ET on April 26, 2026. That's the real timeline. The codebase was authored in Claude Code running Opus 4.7 against the same Managed Agents API the Runner calls in production.
I wrote a lot of this with Claude Code in the loop. I'm going to be specific about what that meant, what it was good at, and where it cost me.
What got built
Final state at submission, give or take a commit:
- A single 1000-line
blscript (compiled from a directory of bash modules I keep separated for sanity, then concatenated for distribution). - 65 markdown skill files across 20 defensive domains.
- A BATS test suite that runs against a curl-shim mock of the Anthropic API, plus a separate live-trace runner that exercises the real surface.
- An installer that's curl-pipe-bash safe, an uninstaller that backs up state, and packaging for
aptandrpm. - A worked APSB25-94 evidence bundle that's deterministic and byte-identical run-to-run, used as a stress corpus for the 1M-context curator.
I had to ship a working pitch, a working install path, and a working end-to-end demonstration on the same artifact. So the project has more polish surface than a four-day build usually justifies. That polish is mostly Claude Code's contribution.
What worked
Specs in the same repo as the code
I wrote a design document and a curator system prompt before the first non-trivial commit. Both files live in the repo next to the source. Every code change that altered the runtime contract updated the design doc in the same commit. The agent could read both and surface divergence as a review observation: "the spec says the Runner validates the schema before executing, but the code in the run dispatcher only validates the verb." That kind of feedback caught a lot of drift I would have missed.
Tests as the agent's feedback channel
The test suite ran against a mock API after every meaningful change. Test failures were the agent's primary feedback channel; the failure message was usually enough context to direct the next edit. I didn't have to keep track of which surfaces were green; the suite did.
This was the most productive part of working with Claude Code. The build loop felt like pair programming with someone who could read the whole codebase faster than I could. Most of my time went into deciding what the next change should be, not implementing it.
The adapter layer (in retrospect)
Every Anthropic API call goes through a tiny set of helper functions in the source. When the Managed Agents beta surface migrated underneath me partway through the build, the migration was contained because almost every call site was already going through one of those helpers. The places where I'd been lazy and called the API directly were the painful ones to migrate.
Had the adapter been there from the first commit, the migration would have been one file's worth of changes. I'd already have it next time.
Stress corpus from public sources only
The end-to-end test depends on a corpus that looks like a real APSB25-94 incident: Apache logs, ModSec audits, filesystem mtime clusters, crontab diffs, process snapshots, journal extracts. Roughly 350,000 tokens of evidence, generated deterministically from a fixed seed using public Adobe advisory IOCs and RFC 5737 IPs. Nothing operator-local ever lands in the repo. The corpus is regenerable, byte-identical run-to-run, and it's what keeps the "1M context as one bundle" claim honest. A 200k-context model couldn't run this case. I needed the headroom.
Anti-patterns I hit and corrected
I trusted the agent's tier classification
The action-tier system originally trusted the agent's tier field directly. The Runner read what the curator wrote and gated accordingly. Then I wrote a synthetic test where the agent classified a clean.cron step as auto, and the Runner would have applied without diff confirmation.
I fixed it by making verb-class re-assert. clean.* is always destructive regardless of what the curator says. The Runner's job is to bound the agent, not to obey it. Trust is layered, never single-source.
"We'll add a live trace before tag"
For most of the build, the project ran end-to-end against a curl-shim mock. The first run against the real Anthropic API was late in the build window, and three of the four scenes in that trace were green. The fourth had drifted in the API beta and I hadn't noticed because the mock was happily returning fixture responses to the broken call.
The lesson was simple and expensive. Mocks substitute for speed, not for truth. Live verification belongs in the cadence, not at the end.
Pitching a feature I didn't have access to
I wrote early framing around Opus 4.7's thinking. The README said "thinking on a 1M-context evidence bundle." POST /v1/agents rejected the field with a 400. Reasoning on Managed Agents is model-internal; it isn't operator-configurable. I rewrote the framing the same evening. The pitch got sharper, not weaker. (Full story is in the pivots doc.)
What Claude Code was good at
Cross-file refactors under a hard constraint. "Migrate every memory-store call to the new adapter helpers; preserve every test's green state." Nine source files, dozens of call sites. The agent held the constraint and worked file-by-file. I'd have been three days slower doing this manually, and I'd have missed something.
Spec-vs-build reconciliation. Pointing the agent at a design-doc section and the corresponding implementation, and asking "do these match?" The agent reads both, identifies the divergence, proposes a reconciliation. A pre-release reconciliation pass surfaced about a dozen of these and I committed them as one cleanup batch.
Test authoring with adversarial intent. "Write a test for the case where the agent emits a destructive step with the auto tier." The agent wrote the failure case before the fix. I committed both.
Skill drafting from public sources. I'd point the agent at a public source (Adobe APSB25-94 advisory, ModSecurity CRS docs, public YARA repos) and ask for a skill draft in the operator voice. Editing the draft was faster than authoring from a blank page. Operator literacy was my editorial filter; if the draft read like generic IR boilerplate, I rejected it and tried a different angle.
What Claude Code needed help with
API surface drift. The agent could not see the API surface had moved. It saw passing tests. The drift was only visible from a real call. This is the gap a live-trace cadence closes, and the gap I'll budget for next time.
A subtle wire-up bug. The cost-cap trace log was being written to the wrong path for many commits before I noticed. The agent didn't catch it because the log was being read by a different code path that worked. Asserting "after an API call, the cost-cap log must be non-empty" as a test would have caught it the day it broke.
Fallback ordering. I added the Sonnet bundle-summary call before I added the deterministic fallback. When Sonnet was rate-limiting in development, every observe command failed. I should have written the fallback first and the LLM-enhanced path second. I do that now.
Output discipline
Two outputs from the agent that I kept verbatim:
-
The curator system prompt. A cross-stream-correlation rule (HIGH/MEDIUM confidence requires citations from at least two distinct evidence streams) came from the agent reading my untrusted-content fence taxonomy and asking, "what's the corresponding hallucination-resistance rule for the curator's output side?" That rule is now doing real work.
-
The bundle-summary system prompt. Sonnet 4.6 generates the summary.md every evidence bundle ships with. The prompt treats log content as untrusted by default, caps output at 2 KB, and requires jump-points and attention-worthy sections. I rewrote the first draft once. The second draft has not changed since.
Cost discipline
The hackathon ran on operator-funded API budget. Discipline mattered.
Sonnet for summaries, not Opus. Haiku for the false-positive gate. A test-mode environment variable that disables LLM calls entirely for the bulk of the BATS suite, so the full mock-backed test run costs zero. Outbox-queued retries with age-gated drain so 429s don't thunder the API.
My last live-trace run cost approximately zero, the curator turn never executed because of the session-creation drift mentioned above. That's not great for verification. It is great for cost cap. When something is broken, I want it to be broken cheaply. The wiring did its job.
Provenance
- Claude model: Opus 4.7 (1M context window) for authoring, with Sonnet 4.6 for codebase navigation and Haiku 4.5 for fixture generation.
- Claude Code as the harness. File edits, BATS test runs, git commits, cross-file refactors.
- Anthropic Managed Agents (
managed-agents-2026-04-01beta) as the production curator runtime. - Hackathon: Anthropic / Cerebral Valley Built with 4.7. Submission window: first commit on this repo through 8 PM ET, April 26, 2026.
Source: github.com/rfxn/blacklight. License: GPL v2.