Writing /Scry /2026-09-11

The Six Kinds of Knowledge a Coding Agent Needs

Source code is only one view of a running system. Useful coding agents also need history, data shape, runtime behavior, test evidence, and the decisions that explain why the system looks this way.

Written by
Read time
6 minutes
Topic
Scry

An agent can read every file in a repository and still misunderstand the system.

The source tells it what exists now. It doesn’t reliably say why a strange branch is there, whether an endpoint is still used, what the production table actually looks like, or which earlier attempt already failed.

I kept running into this while building coding tools. Each gap looked like a search problem until I found the answer sitting in a different system.

Scry indexes six kinds of project knowledge because each one closes a different blind spot.

1. Source structure

The obvious one is code intelligence: definitions, references, callers, callees, implementations, and module relationships.

Agents usually get this information by searching text. That works for names that are unique and codebases that are small. It gets noisy fast. A search for save doesn’t know whether the call belongs to a user model, a repository, or a framework class.

Scry builds a SCIP index ahead of time and stores symbol relationships. A lookup for UserRepository::save returns references to that method rather than every line containing the word. On a representative TypeScript repository, a warm reference query lands in roughly 6 to 7 milliseconds.

The graph built from those symbols answers structural questions before the agent reads implementation detail. Where is this defined? What calls it? Which class fulfills this interface? None of that should require opening twenty search results.

2. Change history and intent

Source structure says what connects. Git often explains why.

Blame is useful, but a line-level author and hash are only the first step. The useful unit is the commit that introduced the line, its message, the other files it changed, and whether those files repeatedly change together.

Scry indexes blame, commit history, contributors, hotspots, and co-change patterns. That last one catches relationships imports can’t. A backend serializer and a mobile type definition may have no static dependency, yet change together in eight consecutive feature commits. That is a real coupling.

The graph can attach code to authors and commits, and commits to database migrations. That gives the agent a direct way to find who has worked in an area and whether a change also touched the schema.

3. Data shape

Migration files aren’t the database.

They may be incomplete, reordered, conditionally applied, or simply stale relative to the environment an agent is debugging. Reading them also forces the agent to reconstruct indexes, nullability, defaults, foreign keys, and inbound references by hand.

Scry introspects MySQL and PostgreSQL directly. It stores tables, columns, indexes, enums, and foreign key relationships. The agent can ask for the shape of orders and get the current answer in one structured result.

The schema gets more useful once it joins the code graph. A function that queries orders can connect to the table and then to customers. An ORM import alone doesn’t describe that relationship very well.

4. Runtime behavior

Static analysis can’t tell you what request actually failed.

Scry can run a local reverse proxy between a browser and a development server. It records request and response pairs with method, path, status, headers, bodies, and timing. Bodies are capped because handing an agent ten megabytes of JSON would create a new problem.

The HTTP domain answers questions like:

  • What was the last POST /api/orders request?
  • Did the client send the field the server claims is missing?
  • Which route is returning 500?
  • Did the response fail before or after authentication?

Observed traffic also gives the graph evidence that a route exists at runtime. That matters in frameworks where routing and handlers are hard to recover through static analysis alone.

5. Verification state

A test file near a function doesn’t mean the function ran.

Scry reads Go coverage profiles, Istanbul JSON, Clover XML, and Python coverage data. It joins executed line ranges to symbol definitions and records whether a function was covered and how many hits it received.

This is intentionally aggregate. It doesn’t try to replace a full coverage dashboard. The coding agent needs a quick answer before changing a function: is there evidence that the current suite exercises this code?

That answer changes the next step. If the function is covered, the agent knows which suite to rerun. If it isn’t, I usually want a focused regression test before the implementation changes.

6. Decisions and lived context

The first five domains can be derived without an LLM. The sixth can’t.

Architecture decisions, machine names, service ownership, failed approaches, and cross-project dependencies tend to live in conversations. Some belong in formal decision records, but most never get one. They appear during a debugging session, matter for three weeks, and disappear when the context window closes.

Scry’s memory domain distills agent transcripts into episodes, then extracts entities and time-stamped facts. An entity can be a project, service, machine, tool, person, decision, runbook, or concept. Facts connect those entities with provenance back to the episode.

This graph can answer “what is Hermes?” or “why did we stop deploying this service on the inference machine?” before the agent asks me to retell the whole story.

Because these facts are inferred, Scry treats them differently from symbol or foreign key edges. They carry confidence, timestamps, and source references. I can inspect the original session if the answer looks wrong.

Why the combination matters

None of these domains replaces another.

Code without history loses intent. History without schema misses data constraints. Static structure without runtime traffic misses actual behavior. Tests without coverage confuse presence with execution. All five without memory force every agent to rediscover project language and old decisions.

The graph connects these domains. A failed endpoint can lead to its handler and the table it queries. From there the agent can inspect the commit that changed it, any coverage attached to the handler, and the old decision behind an odd constraint.

Scry doesn’t always have every edge. Go call graphs are less complete than TypeScript in the underlying SCIP data. Dynamic framework behavior requires post-processing or runtime evidence. Memory extraction can get an entity wrong.

I am fine with gaps as long as Scry shows where each edge came from. The agent can open the source when the graph is incomplete or looks wrong.

The full system is introduced in I Built a Knowledge Graph for Everything I Work On.

Start a project conversation

Email Jeff

Write your note here, then open it in your email app. This site sends nothing: your email app opens with this draft and you press send there. No email app? Copy the address or the draft instead.

Open in your email app ↗

To jeff@hooton.codes · Closing this window discards the draft.