@collivity/aglang
v0.2.2
Published
Architecture Ground Language — agent-facing architecture validation for continuous coding feedback and Z3-backed enforcement
Maintainers
Readme
aglang · Architecture Ground Language
aglang keeps coding agents inside your repository’s architecture rules. Describe topology, components, invariants, workflow policies, and API contracts in a .ag spec file. aglc turns those rules into enforceable checks, then validates implementation work continuously while coding and at commit time.
Designed as an agent-first guardrail: agents read AGENTS.md, validate focused edits with aglc check-file --json, validate the full guarded project with aglc check --all --json, and ask before changing .ag architecture source. Under the hood, hard rules are compiled into solver-backed constraints so violations come with precise proof details instead of vague warnings.
How it works
[Developer / Agent edits code]
│
▼
aglc check-file --json
│
▼
aglc check --all --json
│
▼
git commit / CI gate
│
▼
aglc check ← file/project/diff → extracts flow facts
│
▼
solver-backed gate ← evaluates spec constraints against delta facts
│
┌────┴────┐
SAT UNSAT
│ │
Allow Reject + structured JSON proof- Architecture build —
aglc compile spec.agproducesarchitecture.o(a JSON artifact with SMT-LIB2 constraints + component→path mappings). - Work-in-progress validation — agents run
aglc check-file --jsonwhile editing andaglc check --all --jsonbefore finishing. - Commit enforcement — the pre-commit hook runs
aglc check, extracts flow, reachability, propagated dataflow, trust-boundary, dependency-injection, workflow, and contract facts, feeds formal facts with the compiled constraints to the solver, and blocks the commit if any hard rule is violated. - Agent bootstrap —
aglc addcan create a starter.agspec, compiled artifact, hook, and agent files for engineer review.
The flow is:
- aglc compile architecture.ag parses/typechecks the .ag file and emits architecture.o.
- aglc check --arch architecture.o --project . --all loads architecture.o.
- It expands the component paths globs from the artifact.
- It groups matched files by component.
- It chooses extractors by file extension, for example .ts, .cs, .py, .go, .rs, .java, .kt.
- Extractors emit flow facts, using AST where available and regex fallback where needed.
- Those facts are normalized through graph projection.
- The solver checks the projected flows against the invariant constraints from architecture.o.
If you edit architecture.ag, run npm run arch:compile before npm run arch:check.
Requirements
- Node.js ≥ 18 (WASM-based Z3 solver requires async/WASM support)
- Git (for the pre-commit hook and
aglc check)
Installation
# Global install from npm registry
npm install -g @collivity/aglang
# Install directly from GitHub (public repo, no registry needed)
npm install github:collivity/aglang
# Run without installing
npx @collivity/aglang --helpInstall the generic Codex skill interface for local agents:
aglc install-agent-skillThis copies the packaged aglang skill into ${CODEX_HOME:-~/.codex}/skills. Project-specific rules still come from AGENTS.md and skill.json, generated by aglc add or aglc emit-context / aglc emit-skill.
The npm package also attempts that skill installation during postinstall. Set AGLANG_SKIP_AGENT_SKILL_INSTALL=1 to opt out.
How agents should use aglang
- Read
AGENTS.mdbefore changing implementation code. - Run
aglc check-file --arch architecture.o --file <path> --jsonduring focused edits. - Run
aglc check --arch architecture.o --project . --all --jsonbefore finishing. - Ask before creating, editing, regenerating, or compiling
.agarchitecture specs or generated architecture artifacts. - Use planning/design sessions for architecture authoring so engineers can review intended spec changes.
Quick start
Option A — Agent bootstrap (recommended for existing codebases)
# 1. Scan your project and generate a starter spec (one-shot setup)
npx @collivity/aglang add ./my-project --name MyProject
# The add command runs: generate → compile → install git hook → emit skill.json
# Review my-project/architecture.ag and add invariant rules, then re-run:
aglc compile my-project/architecture.agOption B — Write a spec by hand
// myapp.ag
node web : edge_desktop { trust: untrusted }
node api : server { trust: trusted }
node db : postgres { trust: trusted }
component Frontend {
runs_on: web
paths: "src/frontend/**/*.ts"
}
component Api {
runs_on: api
paths: "src/api/**/*.ts"
}
component Data {
runs_on: api
paths: "src/data/**/*.ts"
}
invariant Layered {
deny flow Frontend -> db // frontend must never touch DB directly
deny flow Api -> db // API layer must go through Data layer
}aglc compile myapp.ag
# ✔ Compiled → architecture.o
# Components: 3 Invariants: 1 Contracts: 0
aglc install --project . --arch architecture.o
# ✔ Installed pre-commit hook → .git/hooks/pre-commitEvery git commit is now checked. Violations are blocked with evidence:
Arch Compilation Error (Rule: Layered)
deny flow Api -> db
Detected: Api → db (definite)
Evidence: ApplicationDbContext injected via constructor
File: src/api/UserService.cs
Commit aborted.Features
| Feature | Status | Description |
|---|---|---|
| Topology nodes | ✅ | Model edge clients, servers, clusters, databases, caches, queues, object stores |
| Components | ✅ | Map source-code globs to topology nodes |
| Flow invariants | ✅ | Deny illegal data flows — checked by Z3 at every commit |
| Contracts | ✅ | Declare REST/GraphQL API endpoint shapes; enforce implements + consumes at commit time |
| GitHub Actions policies | ✅ | Model workflows as components and block unsafe publish/deploy/release permissions |
| Change policies | ✅ | Require related components, docs, skills, or package metadata to change together |
| Dependency injection policies | ✅ | Block illegal constructor injection, singleton-to-scoped dependencies, and service-locator usage with Z3 |
| State machines | ✅ | Model entity lifecycle states and allowed transitions |
| Permissions | ✅ | Declare role-based access rules per state |
| Data & enums | ✅ | Define domain types for documentation |
| Multi-file specs | ✅ | Split large specs with import "other.ag" — shared DAG imports are deduplicated |
| aglc generate | ✅ | Scan any codebase and auto-emit a starter .ag spec (agent bootstrap) |
| Import OpenAPI | ✅ | aglc import-openapi swagger.json → .ag contract blocks |
| Import Terraform | ✅ | aglc import-tf main.tf → .ag node declarations |
| Plugin protocol | ✅ | Extend extraction via npm packages implementing the aglc-plugin protocol |
| Agent context | ✅ | aglc emit-context produces AGENTS.md — machine-verified architectural brief |
| Skill manifest | ✅ | aglc emit-skill produces skill.json for agent tool registries |
| Packaged agent skill | ✅ | aglc install-agent-skill installs a generic Codex skill interface from the npm package |
| Work-in-progress validation | ✅ | Agents run check-file --json during focused edits and check --all --json before finishing |
| JSON verdicts | ✅ | All check commands emit structured JSON with Z3 proofs (--json) |
| Extraction cache | ✅ | SHA-256 keyed file cache in .aglang-cache/ — skips re-analysing unchanged files |
| Parallel extraction | ✅ | All extractors run concurrently (CPU-capped pool) |
Enforcement semantics
Not every declaration is enforced the same way:
| Level | Declarations | Behavior |
|---|---|---|
| formal_z3 | invariant deny flow, invariant deny reach, invariant deny dataflow, data_policy, trust_policy, di_policy, permission, change_policy | Facts are asserted into SMT and checked by Z3 when extractors produce definite evidence. |
| deterministic_policy | contract, workflow_policy | Extracted route/workflow facts are checked by deterministic gates. |
| advisory | machine, permission, require encryption | Emitted to docs and agent context; not blocking until an extractor/gate enforces them. |
This taxonomy is emitted into architecture.o, AGENTS.md, and skill.json so agents know which rules are proof-backed, policy-backed, or guidance-only.
API contracts
Enforce that your backend routes match your frontend expectations:
contract UsersApi {
GET "/api/users" -> User[]
POST "/api/users" -> User
GET "/api/users/{id}" -> User
PUT "/api/users/{id}" -> User
}
component Backend {
runs_on: api
paths: "src/api/controllers/**/*.cs"
implements: UsersApi
}
component Frontend {
runs_on: web
paths: "src/frontend/**/*.ts"
consumes: UsersApi
}The contract gate checks:
- implements — every declared route must be exposed by the component (missing routes = error)
- consumes — the client may only call declared routes (undeclared
fetchcalls = warning)
GitHub Actions workflow policies
Model CI/CD targets as nodes and workflows as components, then enforce release safety directly from .github/workflows/*.yml:
node github_actions : ci_runner { trust: trusted }
node npm_registry : package_registry { trust: trusted auth: api_key }
node github_pages : static_host { trust: trusted auth: oauth2 }
component ReleaseWorkflow {
runs_on: github_actions
paths: ".github/workflows/release.yml"
}
workflow_policy ReleaseSafety {
allow publish ReleaseWorkflow -> npm_registry when tag "v*.*.*"
deny publish * -> npm_registry when pull_request
require before ReleaseWorkflow "npm test" -> "npm publish"
deny permission * contents: write when pull_request
}aglc check reports workflow violations in workflow_violations[]; --workflow-z3 and --dump-workflow-smt add optional SMT debug output for proof-oriented CI runs.
Change policies
Require important surfaces to change together. For example, CLI changes can formally require README and CLI reference updates in the same checked diff:
component CliCompiler {
runs_on: node_runtime
paths: "src/index.ts"
}
component CliReferenceDocs {
runs_on: node_runtime
paths: "docs/cli/reference.md"
}
component ReadmeDocs {
runs_on: node_runtime
paths: "README.md"
}
change_policy DocsFreshness {
require touched CliReferenceDocs when touched CliCompiler
require touched ReadmeDocs when touched CliCompiler
}The gate emits Z3-backed change_violations[] when the trigger component changed but the required companion component did not. This proves declared surfaces changed together; it does not prove prose quality.
Dependency injection policies
Model implementation-level DI hazards as formal architecture rules:
component Views {
runs_on: app_runtime
paths: "src/**/Views/**/*.xaml.cs"
}
component BleManager {
runs_on: app_runtime
paths: "src/**/Infrastructure/Bluetooth/**/*.cs"
}
component Application {
runs_on: app_runtime
paths: "src/**/Application/**/*.cs"
}
di_policy DependencyInjection {
deny inject Views -> BleManager
deny lifetime singleton -> scoped
deny resolve IServiceProvider from Application
}The C# extractor turns constructor dependencies, AddSingleton / AddScoped / AddTransient registrations, and IServiceProvider usage into SMT assertions such as (assert (Injects Views BleManager)). Matching di_policy rules return di_violation entries with Z3 proof details.
.ag language reference
Node types (stdlib)
| Category | Types |
|---|---|
| Client | edge_desktop, edge_mobile, edge_mobile(android), edge_mobile(ios) |
| Server | server, cluster(k8s), cluster(ecs), serverless |
| Database | postgres, mysql, sqlite, relational_db, mongodb, dynamodb |
| Cache | redis, memcached, cache |
| Queue | rabbitmq, kafka, sqs, queue |
| Storage | s3, blob_storage, object_store |
| Network | load_balancer, cdn, api_gateway |
Blocks
// Node
node <name> : <type> {
trust: trusted | untrusted | semi_trusted
connectivity: always_on | intermittent | offline_first // optional
protocol: https | grpc | ws | mqtt // optional
}
// Component
component <name> {
runs_on: <node>
paths: "<glob>"
implements: <ContractName> // optional
consumes: <ContractName> // optional
}
// Invariant
invariant <name> {
deny flow <ComponentOrNode> -> <ComponentOrNode>
deny reach <ComponentOrNode> -> <ComponentOrNode>
deny dataflow <DataType> -> <ComponentOrNode>
require encryption on flow <ComponentOrNode> -> <ComponentOrNode> // advisory
}
// Change policy
change_policy <name> {
require touched <RequiredComponent> when touched <TriggerComponent>
}
// Dependency injection policy
di_policy <name> {
deny inject <Component> -> <Component>
deny inject_reach <Component> -> <Component>
deny lifetime singleton -> scoped
deny lifetime_reach singleton -> scoped
deny resolve IServiceProvider from <Component>
}
// Data and trust policies
data_policy <name> {
deny classification pii -> untrusted
deny jurisdiction eu -> <ComponentOrNode>
}
trust_policy <name> {
require auth untrusted -> trusted
deny flow trusted -> untrusted when data pii
}
// API contract
contract <name> {
GET "/api/path/{param}" -> ResponseType
POST "/api/path" -> ResponseType
PUT "/api/path/{id}" -> ResponseType
DELETE "/api/path/{id}" -> ResponseType
PATCH "/api/path/{id}" -> ResponseType
}
// State machine
statemachine <EntityName> {
states: Draft | Active | Archived
transitions {
Draft -> Active { by: Admin | Editor }
Active -> Archived { by: Admin }
}
}
// Permissions
permission <name> {
<Role> can <action> <Entity> when state = <State>
}
// Data types
data <Name> {
classification: pii
jurisdiction: eu
field: Type
}
enum <Name> { Variant | Variant }
// Multi-file
import "relative/path/other.ag"CLI commands
| Command | Description |
|---|---|
| aglc compile <file.ag> | Compile spec → architecture.o |
| aglc generate [dir] [--out <file.ag>] [--name <n>] | Scan codebase → starter .ag spec |
| aglc check --arch <arch.o> --project <dir> | Check staged git diff (used by hook) |
| aglc check-file --arch <arch.o> --file <path> | Check a single file (dev/debug) |
| aglc emit-context --arch <arch.o> [--out <path>] | Write AGENTS.md (agent context brief) |
| aglc emit-skill --arch <arch.o> [--out <path>] | Write skill.json (agent skill manifest) |
| aglc install-agent-skill [--path <skills-dir>] | Install the packaged generic Codex skill |
| aglc install [--project <dir>] [--arch <arch.o>] | Install pre-commit git hook |
| aglc import-openapi <swagger.json> [--out <f.ag>] | Import OpenAPI 3.x → .ag contracts |
| aglc import-tf <main.tf> [--out <f.ag>] | Import Terraform → .ag node declarations |
Flags:
--json— machine-readable JSON to stdout (progress logs go to stderr)--dump-smt— write the raw SMT-LIB2 script toexamples/debug.smt2
JSON verdict schema (v2)
All check commands emit a JSON object when --json is passed:
{
"schema_version": 2,
"passed": false,
"timestamp": "2026-05-19T09:00:00.000Z",
"artifact": "architecture.o",
"violations": [
{
"type": "reach_violation",
"invariant": "Layered",
"rule": { "kind": "DenyReach", "from": "UI", "to": "Db" },
"detected": {
"from": "UI",
"to": "Db",
"path": ["UI", "Service", "Db"],
"confidence": "definite",
"evidence": "Reachability path: UI -> Service -> Db",
"file": "/abs/path/to/file.cs"
},
"message": "...",
"z3_proof": {
"permanent_constraint": "(assert (=> (CanReach UI Db) false))",
"delta_assertion": "(assert (CanReach UI Db))",
"explanation": "Z3 returned UNSAT — both assertions cannot be simultaneously true"
}
}
],
"contract_violations": [
{
"type": "implements_undeclared",
"severity": "error",
"contract": "UsersApi",
"component": "Backend",
"role": "implements",
"extracted": "DELETE /api/users/{}",
"declared": null
}
],
"change_violations": [
{
"type": "change_violation",
"policy": "DocsFreshness",
"trigger": "CliCompiler",
"required": "CliReferenceDocs",
"message": "DocsFreshness requires CliReferenceDocs when CliCompiler changes"
}
],
"warnings": [],
"contract_warnings": [],
"agent_context": "Human-readable summary for agent consumption"
}Agents & AI integration
aglang is designed as a first-class tool for AI coding agents:
aglc generate— a setup agent runs this once to bootstrap guardrails for any codebase; outputs a compilable.agfile to review and extend.AGENTS.md— generated byaglc emit-context, gives agents a precise brief: topology, component paths, allowed flows, contracts, state machines, and permission rules. Fits in any context window.skill.json— a machine-readable skill descriptor agents can register as a tool.- Packaged Codex skill —
aglc install-agent-skillinstalls the generic aglang interface so agents know the CLI workflows after npm install. - Continuous validation — agents run
aglc check-file --jsonwhile editing andaglc check --all --jsonbefore finishing. - Structured JSON errors — every Z3 violation includes exact file paths, component names, and the Z3 proof object so agents can locate and fix violations without hallucinating.
- Fail-closed — git diff failures and Z3
unknownresults block the commit; nothing is silently allowed. - Engineer-guided architecture source — agents should ask before changing
.ag,architecture.o,AGENTS.md, orskill.json.
Typical agent workflow
1. Setup/design session: aglc generate . --out architecture.ag
→ engineer reviews intended architecture rules
→ authorized run: aglc compile architecture.ag
→ authorized run: aglc install --arch architecture.o
2. Coding agents: read AGENTS.md → edit code
→ run: aglc check-file --arch architecture.o --file <path> --json
→ run: aglc check --arch architecture.o --project . --all --json
→ pre-commit hook fires: aglc check --arch architecture.o --project .
→ agent fixes structured JSON violations in implementation codeSupported extractors
| Language | Extensions | What is extracted |
|---|---|---|
| C# | .cs | Constructor injection (DI), EF Core DbContext, HttpClient, Redis, S3/Blob, MongoDB, Kafka, RabbitMQ, SignalR |
| TypeScript / JS | .ts, .tsx, .js, .jsx | fetch() calls (method + URL), Express/Fastify route declarations |
| Python | .py | SQLAlchemy, Django ORM, psycopg2, Redis, Celery, requests/httpx calls |
| Go | .go | database/sql, GORM, Redis, Kafka, HTTP client calls |
| Rust | .rs | sqlx, diesel, redis, reqwest, tokio |
| Java / Scala | .java, .scala | Spring Data, Hibernate, JDBC, Kafka, Redis, RestTemplate |
| Kotlin | .kt | Retrofit, OkHttp, Room, WorkManager, Ktor |
| Swift / iOS | .swift | URLSession, Alamofire, CoreData, CloudKit, Combine network calls |
All extractors run in parallel with a CPU-capped concurrency pool. Results are cached by file SHA-256 in .aglang-cache/ — unchanged files are never re-analysed.
Plugin protocol
Third-party extractors can be loaded as npm packages:
// In your .ag spec file
plugin "aglc-plugin-my-extractor"Any npm package that exports { info(), extract(input) } and responds to --info / --extract CLI flags qualifies. Run npx aglc — the plugin is auto-discovered and invoked for each file batch matching its declared extensions.
Development
git clone https://github.com/collivity/aglang
cd aglang
npm install
npm run build # tsup -> build/aglc.js
npm test # vitest — 127 tests across 9 test files# Try the bundled Collivity example
node build/aglc.js compile examples/collivity.ag
node build/aglc.js check-file --arch examples/architecture.o --file examples/BadController.cs
node build/aglc.js emit-context --arch examples/architecture.oWhat's left before publishing
The codebase is production-grade in design but still a pre-release (0.1.0). What to do before npm publish:
- Set a GitHub remote —
git remote add origin https://github.com/your-org/aglang - Add
"repository"topackage.json— required by npm - Benchmark extraction accuracy — measure false-positive rate against real codebases
- LSP / VS Code extension —
.agsyntax highlighting and autocomplete - Semantic extraction (stretch goal) — replace regex with Roslyn (C#) / tsc API (TS) for deeper accuracy
License
Apache-2.0 — see LICENSE.
