# artifact-contracts-analyzer

**Analyze project source code through the lens of agent contracts.**

`artifact-contracts-analyzer` bridges the gap between design-time contract definitions (`agent-contracts`) and runtime execution (`agent-contracts-runtime`) by analyzing actual project source code against the contract graph.

It answers the questions that neither the DSL compiler nor the runtime can answer alone:

- What code is actually affected when an artifact changes?
- What context should an agent receive for a given task?
- How do source-level dependencies map to contract-level relationships?

---

## Why artifact-contracts-analyzer?

`agent-contracts` knows the contract graph — which agents own which artifacts, which tools produce or consume them, and what routes a change should follow. But it operates on **DSL definitions only**. It cannot look inside project source files.

`agent-contracts-runtime` knows how to execute agent workflows — task scheduling, SDK adaptation, guardrail enforcement. But it treats context as an **opaque input** provided by the caller.

The missing layer is **source-aware analysis**: reading actual project files, parsing their structure, and connecting code-level dependencies to contract-level relationships.

```text
agent-contracts            artifact-contracts-analyzer       agent-contracts-runtime
(contract graph)           (source analysis)              (execution)

"api-schema's producer     "src/generated/client.ts       "Run implementer with
 is generate-api-client     imports from openapi.yaml.     this context pack and
 tool, and its source       src/handlers/*.ts imports      validate the result."
 is openapi-spec."          from client.ts."

DSL YAML only              DSL + project source files     contracts + context
```

Without this layer, agents either receive too much context (entire repository) or too little (manually curated file lists). Neither scales.

---

## What it does

### 1. AST Graph (low-level)

Parse project source files into a language-aware code structure graph.

```text
Input:
  Project source tree + artifact path_patterns from DSL

Output:
  Code structure graph
  ├── file nodes (kind: "file")
  ├── symbol nodes (kind: "symbol", with symbolId = "filePath#name")
  ├── imports / exports / re_exports edges
  ├── calls edges (caller symbol → callee symbol)
  ├── type_reference edges
  └── contains edges (file → symbol it defines)
```

The AST Graph captures **intra-file structure and inter-file references** at the symbol level. Beyond file nodes, it materializes a node per declared symbol (functions, classes, types, etc.), each identified by a stable `symbolId` of the form `filePath#name` and carrying its 1-based source line range. `contains` edges link a file to the symbols it defines, and `calls` edges connect a calling symbol to the symbol it invokes. It is a raw, deterministic representation of what the code says — no interpretation, no inference.

This is the lowest-level graph in the system. It does not know about artifacts, packages, or contract boundaries. Higher-level graphs consume it.

### 2. Dependency Graph (high-level)

Build a project-wide dependency graph by integrating the AST Graph with package manifests and contract artifact boundaries.

```text
Input:
  AST Graph (code-level edges)
  + package manifests (package.json)
  + artifact path_patterns (from DSL)

Output:
  Unified Dependency Graph
  ├── symbol nodes + symbol-to-symbol edges (calls, type_reference, contains)
  ├── file-to-file edges (from AST Graph)
  ├── external package dependencies (from manifests)
  └── artifact boundary crossings (file → artifact mapping)
```

The Dependency Graph preserves the AST Graph's **symbol nodes and symbol-to-symbol edges** (such as `calls` and `type_reference`) alongside the file and package layers, so a query can drill from artifacts down to individual functions. It is the **integration layer** that connects code structure to contract structure. It answers: "when file A — or the symbol `file#fn` — changes, which other files, symbols, and artifacts are downstream?"

```text
AST Graph                          Dependency Graph
(code structure, symbol-level)     (project structure, artifact-aware)
         │                                  │
         └──────── consumed by ────────────→│
                                            │← package manifests
                                            │← artifact path_patterns
```

### 3. Impact Analysis

Given a changed artifact or set of changed files, compute the **downstream** impact — what is affected by the change.

```text
Input:
  Navigation Index (from agent-contracts)
  + Dependency Graph
  + change seeds: changed files, changed symbols, an artifact ID,
    or a git diff ref

Output:
  Impact Report
  ├── affected entries (AffectedEntry: path, plus symbolId and line/endLine
  │     when the affected node is a symbol)
  ├── directly affected files (immediate dependents)
  ├── transitively affected files (downstream closure)
  ├── affected artifacts (mapped back to DSL)
  ├── affected validations (from artifact required_validations)
  ├── affected agents and workflows
  └── confidence annotations per edge
```

Change seeds can be specified at multiple granularities:

- **Files** (`--files`) — whole-file change seeds, as before.
- **Symbols** (`--symbols`) — symbol-level seeds of the form `src/server.ts#handleRequest`, so impact starts from a single function rather than the whole file.
- **Git diff** (`--diff <ref>`) — derives changed symbols automatically by diffing against a ref (e.g. `HEAD~1`, `main`), mapping each changed line range back to the symbol whose source range contains it.

Each result is an `AffectedEntry` carrying the file `path`; when the affected node is a symbol it also carries its `symbolId` and `line`/`endLine` range, so consumers know exactly which declarations are in scope.

Impact Analysis traces **reverse dependencies** from the change point outward:

```text
changed file/artifact
  → reverse references (who imports/calls this?)
  → affected callers (downstream transitive closure)
  → affected artifacts (mapped via path_patterns)
  → affected validations (from artifact required_validations)
  → affected agents/workflows (from Navigation Index routes)
```

The default direction is **downstream impact** — what breaks or needs updating when this changes. Upstream analysis (what does this depend on?) is available as a separate query mode but is not the primary use case.

The Navigation Index provides contract-level relationships (tool operations, artifact relations, action routes). The Dependency Graph provides code-level relationships. Impact Analysis overlays both to determine the full scope of a change.

### 4. Context Pack Generator

Produce a minimal, relevant context pack for an agent task — the right files, the right sections, the right metadata.

```text
Input:
  Impact Report (or task + artifact scope)
  + Dependency Graph
  + project source files

Output:
  Context Pack
  ├── relevant source files (ranked by relevance)
  ├── relevant artifact definitions
  ├── dependency context (what depends on what)
  └── size budget enforcement
```

Instead of passing an entire repository or relying on manual file lists, the Context Pack Generator uses graph analysis to select the minimal set of files an agent needs to complete a task effectively.

Two extraction granularities are supported (`--granularity`):

- **`symbol`** (default) — only the line ranges of the affected symbols are extracted.
- **`file`** — each selected file is included in full. `extractSymbolSections` turns the impact report's affected symbols into one section per symbol (spanning its `line`…`endLine`), sorted and de-overlapped, so the pack carries the relevant functions and types rather than whole files. This packs far more relevant context into the same token budget.

### 5. Provenance and Evidence Model

Every edge in the graph carries provenance metadata: an **edge classification** and an array of **evidence** recording *why* the edge exists.

The graph build produces **deterministic edges** from static AST analysis, manifests, and path pattern matching. Each edge carries structured evidence:

```yaml
edge:
  from: src/routes/api.ts
  to: src/services/user-service.ts
  type: deterministic
  source: ast_import
  confidence: 1.0
  evidence:
    - type: static_import
      detail: "import { UserService } from '../services/user-service'"
      line: 3
```

`computeRelevanceScore` assigns each edge a relevance score from the *kinds* of evidence backing it (e.g. `static_import` outweighs heuristic links), with a bonus when several distinct evidence kinds corroborate the same edge.

**`artifact-analyzer semantic`** detects gaps in the deterministic graph and proposes **candidate edges** via LLM inference. Candidate edges are persisted to the store and automatically merged into the graph on subsequent `impact` and `context-pack` runs. Use `--edge-types deterministic` to exclude them.

### 6. Call Graph

Walk the `calls` edges from an entry symbol to build a bounded call tree. The traversal runs in either direction:

- **Forward** (default) — follow `calls` edges caller → callee: *"what does this function call, transitively?"* Useful for understanding a function's full call chain before changing it.
- **Reverse** — follow `calls` edges callee → caller: *"who calls this function, up to the entry points?"* Callers surface at the leaves. Useful for verifying test coverage (which tests reach this symbol?) and assessing blast radius.

Cycles (recursion, mutual recursion) are detected per root-to-node path and truncated, so the tree is always finite, and traversal is bounded by a maximum depth.

```bash
# Forward: what does handleGet call, up to 3 levels deep?
artifact-analyzer callgraph --entry 'src/api.ts#handleGet' --depth 3

# Reverse: who calls parse() — including which tests reach it?
artifact-analyzer callgraph --entry 'src/utils.ts#parse' --direction reverse
```

The global `--format` selects the rendering: an indented tree (`text`), a Graphviz digraph (`dot`), or the raw tree structure (`json`).

---

## Architecture

### Inputs and outputs

```text
┌─────────────────────────┐     ┌──────────────────────────┐
│ agent-contracts          │     │ Project Source Tree       │
│                          │     │                          │
│ resolve() ───────────────┼──┐  │ src/, lib/, tests/, ...  │
│ buildNavigationIndex() ──┼──┤  │ package.json             │
│                          │  │  │ config files             │
└─────────────────────────┘  │  └──────────┬───────────────┘
                             │             │
                             ▼             ▼
                    ┌──────────────────────────────┐
                    │ artifact-contracts-analyzer      │
                    │                              │
                    │ buildAstGraph()       (low)  │
                    │     ↓                        │
                    │ buildDependencyGraph() (high) │
                    │     ↓                        │
                    │ analyzeImpact()              │
                    │     ↓                        │
                    │ generateContextPack()        │
                    └──────────────┬───────────────┘
                                   │
                    ┌──────────────┼───────────────┐
                    ▼              ▼               ▼
              Impact Report   Context Pack   Dependency Graph
                    │              │
                    ▼              ▼
            ┌─────────────────────────────┐
            │ agent-contracts-runtime      │
            │                             │
            │ runWorkflow(invocation, {   │
            │   contextPack: pack         │
            │ })                          │
            └─────────────────────────────┘
```

### Internal data flow

```text
Source files ──→ AST Graph (symbol-level, deterministic)
                    │
                    ├── + package manifests
                    ├── + artifact path_patterns
                    ▼
               Dependency Graph (project-level, artifact-aware)
                    │
                    ├── + Navigation Index (contract-level)
                    ├── + changed files
                    ▼
               Impact Report (downstream closure + evidence)
                    │
                    ├── + source file contents
                    ├── + token budget
                    ▼
               Context Pack (optimized agent input)
```

### Package dependencies

```text
artifact-contracts-analyzer
  dependencies:
    agent-contracts         — resolve(), buildNavigationIndex(), DSL types
  peerDependencies:
    better-sqlite3          — optional: persistent index store (in-memory fallback)
```

`artifact-contracts-analyzer` depends on `agent-contracts` for DSL resolution and the Navigation Index API. It **does not depend on `agent-contracts-runtime`** — runtime integration lives in a separate package (`artifact-contracts-analyzer-plugin`), so the analyzer can be used standalone for impact analysis and dependency visualization.

### Boundary with agent-contracts

| Concern | agent-contracts | artifact-contracts-analyzer |
|---------|----------------|--------------------------|
| Input | DSL YAML (+ cli-contract YAML) | DSL + project source files |
| Contract Graph | Builds from DSL | Consumes as input |
| Navigation Index | Builds from DSL | Consumes as input |
| AST analysis | None | Core capability |
| File system scanning | `artifact-coverage` (pattern matching only) | Deep source analysis |
| Impact analysis | None | Core capability |
| Context generation | Template rendering (Handlebars) | Graph-based context selection |

### Boundary with agent-contracts-runtime

| Concern | agent-contracts-runtime | artifact-contracts-analyzer |
|---------|------------------------|--------------------------|
| Agent execution | Core capability | None |
| SDK adaptation | Core capability | None |
| Workflow DAG scheduling | Core capability | None |
| Context pack consumption | Receives and passes to agents | Produces |
| Plugin system | Provides `AgentPlugin` interface | Bridged by separate `artifact-contracts-analyzer-plugin` package |
| Guardrail enforcement | Core capability | None |

### Runtime plugin integration

Runtime integration is provided by a **separate package**, `artifact-contracts-analyzer-plugin`, which depends on both the analyzer and `agent-contracts-runtime`. The analyzer core stays free of runtime knowledge:

```typescript
import { createAnalyzerPlugin } from 'artifact-contracts-analyzer-plugin';
import { pluginRegistry } from 'agent-contracts-runtime';

const plugin = createAnalyzerPlugin({
  projectRoot: '.',
  index: prebuiltIndex,
});

pluginRegistry.register(plugin);
```

The plugin implements the `AgentPlugin.contextEnhancer` interface — no changes to `agent-contracts-runtime` are required.

---

## Deterministic-first principle

The graph build produces **deterministic edges** from code structure:

| Priority | Method | Confidence | Example |
|----------|--------|------------|---------|
| 1 | Static AST analysis | 1.0 | `import { foo } from './bar'` |
| 2 | Manifest resolution | 1.0 | `dependencies` in `package.json` |
| 3 | Path pattern matching | 1.0 | `path_patterns: ["src/generated/**"]` |

`artifact-analyzer semantic` can propose **candidate edges** via LLM inference for gap detection. Candidate edges are persisted and merged into subsequent pipeline runs. Use `--edge-types deterministic` to restrict to confirmed relationships only.

---

## Capabilities

### CLI

```bash
# Build and display the AST dependency graph
artifact-analyzer graph --project-root .

# Analyze impact of changes to a specific artifact
artifact-analyzer impact --artifact api-schema

# Analyze impact of specific file changes
artifact-analyzer impact --files src/api/schema.ts src/api/types.ts

# Analyze impact starting from a single symbol
artifact-analyzer impact --symbols 'src/server.ts#handleRequest'

# Derive changed symbols from a git diff and analyze their impact
artifact-analyzer impact --diff HEAD~1

# Build a forward call graph rooted at a symbol
artifact-analyzer callgraph --entry 'src/api.ts#handleGet' --depth 3

# Build a reverse call graph (who calls this symbol?)
artifact-analyzer callgraph --entry 'src/utils.ts#parse' --direction reverse

# Generate a context pack (symbol-scoped by default)
artifact-analyzer context-pack --files src/api.ts --task implement-feature --budget 50000

# Generate a file-granularity context pack
artifact-analyzer context-pack --files src/api.ts --granularity file

# List dependencies of a file
artifact-analyzer dependencies --file src/api.ts --format json
```

### Library API

```typescript
import {
  buildAstGraph,
  buildDependencyGraph,
  createDefaultRegistry,
  analyzeImpact,
  buildCallGraph,
  generateContextPack,
} from 'artifact-contracts-analyzer';

// Artifact patterns: artifactId → glob patterns (from DSL path_patterns).
const artifactPatterns = new Map([
  ['api-schema', ['src/generated/**']],
  ['handlers', ['src/handlers/**']],
]);

const registry = createDefaultRegistry();

const { graph: ast, fileContents } = await buildAstGraph({
  projectRoot: '.',
  artifactPatterns,
  registry,
});

const graph = await buildDependencyGraph({
  ast,
  projectRoot: '.',
  artifactPatterns,
  manifests: ['package.json'],
});

// Symbol-level impact: seeds may be files OR symbolIds ("filePath#name").
const impact = await analyzeImpact({
  graph,
  changed: ['src/server.ts#handleRequest'],
  direction: 'downstream',
});

for (const entry of impact.directlyAffected) {
  if (entry.symbolId) {
    console.log(`${entry.symbolId} (lines ${entry.line}-${entry.endLine})`);
  }
}

// Call graph: who calls this symbol, up to the entry points?
const callGraph = buildCallGraph({
  graph,
  entry: 'src/utils.ts#parse',
  direction: 'reverse',
  maxDepth: 3,
});

// Context pack: symbol-scoped by default.
const contextPack = await generateContextPack({
  graph,
  changed: ['src/server.ts#handleRequest'],
  taskId: 'implement-feature',
  budgetTokens: 50_000,
  projectRoot: '.',
  fileContents,
});
```

---

## Who this is for

`artifact-contracts-analyzer` is a fit for teams that:

- use `agent-contracts` to define multi-agent workflows
- want agents to receive **optimized, relevant context** instead of entire repositories
- need **impact analysis** to understand what a change affects before delegating to agents
- operate at scale where manual context curation is not sustainable
- want to integrate source analysis into existing `agent-contracts-runtime` workflows

### Who this is not for

- Teams not using `agent-contracts` — the analyzer requires a contract graph as input
- Single-file or trivial projects — the overhead of graph analysis exceeds the benefit
- Teams that need only runtime orchestration — use `agent-contracts-runtime` directly

---

## Relationship to the ecosystem

```text
┌────────────────────────────────────────────────────────────────┐
│                    agent-contracts ecosystem                    │
│                                                                │
│  ┌──────────────┐  ┌─────────────────┐  ┌──────────────────┐  │
│  │              │  │                 │  │                  │  │
│  │   agent-     │  │    agent-       │  │    agent-        │  │
│  │  contracts   │──│  contracts-     │──│  contracts-      │  │
│  │              │  │   analyzer      │  │   runtime        │  │
│  │  (design)    │  │  (analysis)     │  │  (execution)     │  │
│  │              │  │                 │  │                  │  │
│  └──────────────┘  └─────────────────┘  └──────────────────┘  │
│                                                                │
│  DSL → Contract    Contract Graph →    Contracts + Context →  │
│  Graph             Source Analysis →   SDK Execution →         │
│                    Context Pack        Validated Results       │
└────────────────────────────────────────────────────────────────┘
```

The three packages form a pipeline:

1. **`agent-contracts`** — define what the system looks like (contracts)
2. **`artifact-contracts-analyzer`** — understand what the code looks like (analysis)
3. **`agent-contracts-runtime`** — execute agent tasks with optimal context (execution)

Each package is independently useful, but the combination enables **contract-aware, source-optimized agent execution**.

---

## AST cache

The analyzer caches per-file AST parse results keyed by content hash (SHA-256). On subsequent invocations, only files whose content has changed are re-parsed. The cache is stored locally (SQLite with in-memory fallback) and can be inspected or cleared via `artifact-analyzer cache status` / `cache clear`.

---

## Evidence model

Every edge in the graph carries structured evidence explaining **why** the relationship exists:

```yaml
edge:
  from: src/routes/api.ts
  to: src/services/user-service.ts
  type: deterministic
  source: ast_import
  confidence: 1.0
  evidence:
    - type: static_import
      detail: "import { UserService } from '../services/user-service'"
      line: 3
```

Evidence types include `static_import`, `manifest_dependency`, `path_pattern_match`, and others. This makes every edge **auditable** (reviewers can inspect why two files are linked) and **debuggable** (unexpected impact results can be traced to their evidence).

---

## Tech stack

| Category | Choice |
|----------|--------|
| Language | TypeScript (ESM, strict mode) |
| AST parsing | TypeScript Compiler API (built-in) |
| Cross-file resolution | TypeScript Compiler API via `ProjectAnalyzer` (resolves `calls`/`type_reference` targets to cross-file symbolIds) |
| Graph | In-memory adjacency graph with serialization |
| Schema | Zod |
| CLI | commander |
| Testing | Vitest |
| Build | tsup |

---

## Status

This project is **implemented and usable** for TypeScript/JavaScript projects. The full pipeline — AST graph, dependency graph, impact analysis, call graph, and context pack generation — is available through both the `artifact-analyzer` CLI and the library API, including symbol-level analysis (symbol nodes, `calls` edges, symbol-level impact seeds, git-diff-derived seeds, and symbol-scoped context packs). A runtime plugin bridge (`artifact-contracts-analyzer-plugin`) is provided as a separate package. As a pre-1.0 release, the API surface may still evolve.

---

## License

MIT
