Package Exports
- agent-gov-core
- agent-gov-core/schemas/finding.schema.json
- agent-gov-core/test-utils
Readme
agent-gov-core
Shared primitives for the AI-agent governance suite — a small library that ScopeTrail, PolicyMesh, CapabilityEcho, TaskBound, and SessionTrail all consume so common parsers, locators, and the Finding schema live in one place instead of five.
Zero runtime dependencies. ESM, TypeScript, target ES2022.
Install
npm install agent-gov-coreThe canonical Finding
Every tool in the suite emits findings against the same schema. The kind field is a namespaced string <tool>.<slug> so a downstream meta-reviewer can dedupe across tools.
Emit a finding
import { createFinding } from 'agent-gov-core';
const finding = createFinding({
tool: 'scope_trail',
name: 'permission_allow_widened',
severity: 'high',
message: 'Claude permission allowlist now includes Bash(npm *).',
location: { file: '.claude/settings.json', line: 12 },
});
// finding.kind === 'scope_trail.permission_allow_widened'
// finding.fingerprint === '<stable 16-char hex>'createFinding calls kind() to build the namespaced kind, validates the slug shape, and computes a stable fingerprintFinding(finding) hash of (kind, file, line, column).
Validate findings from disk
A downstream meta-reviewer that ingests JSON reports from multiple tools can check each finding against the schema before merging:
import { validateFinding } from 'agent-gov-core';
import { readFileSync } from 'node:fs';
const report = JSON.parse(readFileSync('scopetrail-report.json', 'utf8'));
for (const f of report.findings) {
const result = validateFinding(f);
if (!result.ok) {
console.error(`Skipping malformed finding: ${result.errors.join('; ')}`);
continue;
}
// ... merge into cross-tool inbox keyed by f.fingerprint ...
}Schema is the contract
The JSON schema at schemas/finding.schema.json is the single source of truth for the dotted-kind shape, the closed tool enum, and the location fields. Any tool emitting unprefixed kinds will fail validation. See CONTRIBUTING.md for how the TypeScript types and JSON schema are kept in lockstep.
What's in the library
Finding schema and helpers
Finding,Severity,ToolKind,FindingLocation— canonical typesSEVERITIES,TOOL_KINDS— runtime arrays of the enum valuesisSeverity(v),isToolKind(v),isNamespacedKind(v)— type guardskind(tool, name)— build a namespaced kind without hand-assembling the dotted stringcreateFinding({tool, name, severity, message, ...})— convenience constructor that callskind()andfingerprintFinding()for youfingerprintFinding(finding)— 16-character hex hash of(kind, file, line, column). Stable across runs and message rewordings, so a meta-reviewer can dedupevalidateFinding(value)— runtime check againstschemas/finding.schema.json, returns{ ok, errors[] }
Config readers
readJsonObjectWithSource(path)— JSONC reader, string-aware comment + trailing-comma stripping, position-preserving. Returns{ value, json, text, parseError? };valueandjsonreference the same parsed object —jsonis kept as a deprecated alias.stripJsonComments(text)— same logic exposed for in-memory textreadTomlObject(path)— TOML reader (sections, arrays of tables, inline tables, multi-line strings, dotted/quoted keys). Returns{ value, toml, text, parseError? };valueandtomlreference the same parsed object —tomlis kept as a deprecated alias.parseToml(text)— same exposed for text
Line locators
lineOfJsonKey(text, key, scope?)— 1-based line of"key":, optionally scoped to a byte rangelineOfJsonStringValue(text, value, scope?)— 1-based line of a JSON-encoded value, optionally scoped to a byte rangelineOfTomlKey(text, dottedKey, scope?)— 1-based line of a TOML key, optionally scoped to a byte range. Use scope to disambiguate[[array]]-of-tables entries that share the same leaf key.
MCP command normalization
normalizeMcpCommand({ command, args, url, serverUrl, env, cwd })— canonical identity string for an MCP server entry. Drops neutral flags (-y,--yes), resolves npx/uvx invocations, includes env+cwd in the identity. Used to dedupemcp_command_mismatchfalse positives when servers are equivalent but syntactically different (npx -y foo@1.2.3vsnpx foo@1.2.3).
Shell tokenization
tokenizeShell(command)— quote-aware split on;,|,&&,||plus trivial obfuscation neutralization (c""url→curl,c\\url→curl)getCommandHead(subcommand)— extract the leading verb after tokenization
GitHub Action helpers
rankSeverity(s)— numeric ranknone=0 … critical=4passesSeverityThreshold(s, threshold),anyAtOrAbove(findings, threshold)— fail-on plumbingemitFindingAnnotation(f)— render a Finding as a::warning file=…,line=…,title=…::…GitHub workflow annotation
Test fixtures (agent-gov-core/test-utils)
Secondary entry point used by consumer test suites. Zero overhead in production — only loaded when test files import it.
writeFiles(dir, { relPath: content })— write a map of files underdir, creating parent directoriesmakeGitRepo({ initialFiles?, initialMessage? })→{ repo, commit, head, git, cleanup }— temp repo on branchmainwith placeholder identity;commit()writes files and commits, returning the new SHAmakeOldNewFixture({ old, new })→{ old, new, cleanup }— two sibling temp directories for diff-mode CLI tests
Principles
- Zero runtime dependencies. Real TOML, JSONC, MCP normalization, shell tokenization — all hand-written or vendored, no transitive supply chain.
- MIT. No telemetry. No network calls anywhere in the library.
- Semver, with the contract frozen at v1.0. Until then, minor versions may include breaking changes (the v0.2 schema regex tightening is one example).
- Per-tool reasoning stays in each tool. This library is the substrate, not the orchestrator.
Used by
- ScopeTrail — agent permission drift in PRs (
scope_trail.*findings) - PolicyMesh — cross-surface agent policy contradictions (
policy_mesh.*) - CapabilityEcho — capability drift through code, not config (
capability_echo.*) - TaskBound — scope creep after the agent runs (
task_bound.*) - SessionTrail — runtime behavior across agent session transcripts (
session_trail.*)
Contributing
See CONTRIBUTING.md for the dev workflow, "adding a detector" walkthrough, the dist/release rules, and the cross-tool dogfooding contract.
Per-release notes live in CHANGELOG.md.
License
MIT.