@attalabs/aeg-core
v0.41.0
Published
The pure, no-I/O core of the AEG (Agentic Engineering Governance) engine.
Readme
@attalabs/aeg-core
The pure, no-I/O core of the AEG (Agentic Engineering Governance) engine.
Two capabilities, plus two small non-pure helpers:
Parse a repo's AEG artifacts — registry, tranche files, Issue/PR bodies, doc-owners bindings — into a typed model.
Derive —
deriveTranche(tranche, forgeFacts)produces per-task derived status, the dependency/conflict graph, and dispatch eligibility. Status is never stored; it is always derived from forge facts.ensureLabelExists(src/ensure-label.ts) — the idempotent "list, check, create" decision shared by every forge label-minting call site in this repo. Callers inject their ownlistLabelNames/createLabelI/O so this stays agnostic to shell mechanism and error-handling policy.hardenedMeteringDeps(src/metering-io-guard.ts) — theMeteringCapabilityDepsevery real caller ofresolveMeteringCapabilityshould build from, rather than hand-rollingexistsSync/readFileSync. Refuses a symlink, a FIFO/blocking special file, or a foreign-owned file at the transcript-pointer path (O_NOFOLLOW | O_NONBLOCK+ anfstatowner check) instead of following/hanging on/trusting one.claude-code-transcript.tsitself stays pure — this is a sibling module, the one other deliberate exception alongsideensure-label.tsto this package otherwise being no-I/O.The Vinaya Log's typed policy layer (
src/log/) —LogEventSchema(a zod union over the ten families:dispatch,dev_review_loop,forge_write,gate,operation,usage,role_attempt,handoff,effect, andcustom), the purebuildHeader(input)envelope builder, andredact(value, home). No filesystem, network, or process here; the one write lives in@attalabs/vinaya'sapps/cli/src/lib/log-sink.ts(apps/cli/specs/log.md).The dev-review-loop's policy half (
src/dev-review-loop/) —assessRound(state, observations)decides every transition of the developer/reviewer/CI loop (dispatch the developer, dispatch reviewers, ask for confidence, publish, or pause with a reason) and returns theDevReviewLoopEvents for the caller to pass to the injectedlog();renderPublishedMarker(journal, head)renders the publication comment (one hidden marker line: the published head and each round's confidence — no round table) with no finding text and no line either verdict extractor would read as a real verdict. No filesystem, network, process, or vendor reference anywhere in this directory — the driver (dispatching the developer/reviewers, running CI, callinglog()) lives elsewhere.The task tools' catalog (
src/task-tools.ts) — one typed entry per tool the task Operator may call, each carrying thepurposeandboundariestext a server composes into the description it serves (apps/cli/src/lib/task-tools/server.ts), plusOPERATOR_TOOL_GRANT, the closed set of tools that Operator holds. That text is the only documentation the caller is served, so it states which run states a tool acts on and names the tool that owns each one it does not — a caller handed a refusal always has a next tool to call, and a state one tool continues is never described as another's. Where the path a tool launches is weaker than the tool that owns a state (a continuation that accepts any standing ruling, say, against one that requires a ruling newer than the pause it answers), the text says so rather than implying a gate the launched path does not have.
The bin/ directory carries the check binaries (verify-dispatch, verify-docs, verify-coherence, open-pr, open-issue, …) that mechanize the AEG gates. They are consumed through the @attalabs/vinaya CLI, which bundles this package at build time. verify-dispatch's Depends-on/Conflicts-with resolver understands three edge shapes — a same-tranche bare task id, a bare #NNN Issue reference, and the cross-tranche <slug> <n> form — resolving the last one via the same tranche derivation used for the task's own tranche; an edge matching none of these reports UNRESOLVABLE rather than being read as an unmerged dependency. dispatch-gate.ts's and coherence-checks.ts's failures each carry a closed, machine-readable class (DispatchBlockerClass, CoherenceFailureCode) beside the human message string, so a consumer's recovery-prompt switch can be exhaustive over it rather than parsing message text — a new class with no matching prompt fails typecheck instead of silently routing to the wrong advice.
Two src/*.test.ts files double as self-audit gates over this package's own tree, both src/ and bin/: symbol-collisions.test.ts refuses a name declared in more than one non-test source file (a baselined KNOWN_COLLISIONS set covers what's already there), and no-binary-sources.test.ts refuses a tracked file that git treats as binary — either a literal NUL byte or a .gitattributes binary marking.
This package is published as TypeScript source (main points at ./src/index.ts) — consume it with Bun or a TS-aware bundler, not plain Node.
Part of the fixed release group @attalabs/aeg-types / @attalabs/aeg-forge-state / @attalabs/aeg-core / @attalabs/vinaya-sources / @attalabs/vinaya: all five always share one version, and internal dependencies are pinned exactly.
License
Licensed under the Functional Source License, Version 1.1, with an Apache-2.0 future license (FSL-1.1-ALv2) from version 0.35.0 — see LICENSE. Versions 0.34.0 and earlier were released under Apache-2.0 and stay Apache-2.0.
