Metadata-Version: 2.4
Name: ai-constitution
Version: 0.1.3
Summary: Constitutional governance framework for AI agents — parameterized templates rendered once at onboarding
Author: Vishal Raj
License: MIT
Project-URL: Homepage, https://github.com/vraj0703/ai-constitution
Project-URL: Repository, https://github.com/vraj0703/ai-constitution
Project-URL: Issues, https://linear.app/raj-sadan/project/ai-constitution
Keywords: ai,agent,governance,constitution,claude,ollama
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: jinja2>=3.1
Requires-Dist: tomli>=2.0; python_version < "3.11"
Requires-Dist: pydantic>=2.5
Provides-Extra: dev
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: pytest-cov>=4.1; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Dynamic: license-file

# ai-constitution

> A constitutional governance framework for AI agents. Bring your own organization name.

[![CI](https://github.com/vraj0703/ai-constitution/actions/workflows/ci.yml/badge.svg)](https://github.com/vraj0703/ai-constitution/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Python: 3.10+](https://img.shields.io/badge/Python-3.10+-blue.svg)](pyproject.toml)

Most AI agent setups bake the agent's name, the operator's name, and infrastructure details directly into prompt files. Cloning the same governance pattern for a new organization means find-and-replace by hand and hoping you didn't miss anything.

This repo separates the framework — the universal pattern for principal authority, ministries, sherpas, protocols, and lifecycle — from the organization that uses it. One config file (`org-config.toml`) drives a lossless render of the entire constitution into your own copy.

It's the framework half of a three-repo stack:

| Repo | Role |
|---|---|
| **ai-constitution** (this) | Articles, protocols, command surface, render pipeline |
| [**ai-ministers**](https://github.com/vraj0703/ai-ministers) | Domain-expert minister skills (planning, design, external affairs, resources, review) |
| [**ai-sherpa**](https://github.com/vraj0703/ai-sherpa) | Execution sherpas (boot, exit, onboarding, plus optional scrum, design, nextcloud, crawler) |

> **Status:** v0.0.1. The render API and 24 templates are populated. Onboarding sherpa lands in M3 (RAJ-61). [Public roadmap in Linear](https://linear.app/raj-sadan/project/ai-constitution).

---

## If you've never built an agent before

Think of an organization. There's a person at the top — call them the *principal* — who has authority and sets direction. Below them is a *principal secretary*: an aide who organizes the work, delegates to specialists, keeps the calendar, and makes sure decisions get carried out.

In this framework, the principal is you (the human). The principal secretary is your AI agent. The specialists are *ministers* (each one expert in a domain — planning, design, etc.). The errand-runners are *sherpas* (each one wraps a concrete operation: starting services, shutting down, onboarding a new colleague).

The agent doesn't decide everything itself. When a task comes in, it figures out which minister's domain it belongs to, delegates the thinking, and uses sherpas to execute the result. The principal stays in charge — every decision routes back through them.

The reason this exists: when you write all of that down once as text — articles, protocols, identity — and parameterize the names, any organization can adopt the same pattern. You don't fork prompts; you fill in a config file.

Three repos, four files, one render. That's it.

---

## If you're building agents

The framework is text + a small Python render layer. Here's the shape:

```
ai-constitution/
├── ai_constitution/          # Python: Constitution.load + render API
├── templates/                # 24 jinja2 templates lifted from raj-sadan
│   ├── CONSTITUTION.toml.j2  # 20 articles
│   ├── AGENT.toml.j2         # operating system for the agent
│   ├── IDENTITY.toml.j2      # the agent's persona
│   ├── PRINCIPAL.toml.j2     # the human at the top
│   ├── CLAUDE.md.j2          # bootloader prompt for Claude Code
│   ├── boot-prompt.md.j2     # session boot template
│   └── protocols/PROTOCOL-*.toml.j2   # 13 protocols, "00".."12"
├── skills/                   # 5 lifecycle commands as Claude Code skills
│   └── {amend, boot, checkpoint, delegate, reboot}/SKILL.md.j2
├── defaults.toml             # baseline values for every variable
└── ai_constitution/schema.py # Pydantic models for org-config.toml
```

### How rendering works

1. The framework ships templates with `{{ org.* }}` placeholders.
2. The consumer writes `org-config.toml` (or runs the onboarding sherpa to generate it).
3. `ai_constitution.Constitution.load(...)` reads `defaults.toml`, merges the consumer's overrides, validates against the Pydantic schema, and renders every template into a target directory.
4. The output is plain TOML and Markdown — no template engine ships into the consumer's runtime.

### Quick start

```bash
pip install ai-constitution

# Render a default "Your Org" bundle just to see the shape
python -m ai_constitution render --output ./my-bundle/

# Or with overrides
python -m ai_constitution render --config my-org.toml --output ./my-bundle/

# Validate an org-config without rendering
python -m ai_constitution validate --config my-org.toml

# See what would change vs. an existing bundle
python -m ai_constitution render --config my-org.toml --output ./my-bundle/ --diff
```

### The variable registry

Every value an organization can override lives under `org.*`:

```toml
[org]
name     = "Acme"
slug     = "acme"
timezone = "Europe/Madrid"

[org.pm]
name  = "Vishal"
title = "Founder"

[org.agent]
name  = "Friday"
emoji = "🤖"

[org.ministries]
enabled = ["planning", "design", "review"]   # subset of the ai-ministers registry

[org.sherpas]
enabled = ["boot", "exit", "onboarding"]     # mandatory three; opt in to more

[org.protocols]
enabled = ["00", "12"]                       # minimum viable: delegation + cognitive continuity
```

Full registry in [CONTRACTS.md](CONTRACTS.md). Every variable has a default, so a partial override is fine.

### Three-repo relationship

- **ai-constitution** ships the framework + render pipeline. It depends on nothing else.
- **ai-ministers** ships the prompt skills. The render pipeline pulls in only the ministers in `org.ministries.enabled`.
- **ai-sherpa** ships the execution code. The onboarding sherpa lives here and calls into `ai_constitution.Constitution.load + render`.

A consumer adopts all three as git submodules (or pip-installs the published packages) and points the renderer at their own `org-config.toml`.

---

## If you're integrating it into something larger

A few design notes worth knowing before you write code against this:

**The render contract is lossless.** Same inputs always produce the same bytes. `StrictUndefined` is on, so a typo in a template raises `UndefinedError` instead of silently rendering empty. Idempotent re-renders are tested.

**Validation lives in two places, deliberately.** The Pydantic schema (`ai_constitution.schema`) catches type errors and unknown fields at config-load time. "Required-ness" — refusing to proceed when `org.name` is still `"Your Org"` — is the onboarding sherpa's job, not the schema's. This keeps the schema reusable for non-interactive renders (CI pipelines, programmatic tests).

**Auto-derivation only fills empties.** If `org.slug` is empty, the renderer derives it from `org.name` (kebab-case, max 64 chars). If you set `org.slug` explicitly, your value wins. Same for `org.agent.reports_to` (defaults to `org.pm.title`).

**Mandatory sherpas are auto-added.** Even if a consumer omits `boot`, `exit`, and `onboarding` from `org.sherpas.enabled`, the schema adds them back. They're load-bearing for the lifecycle.

**No conditional templates.** Every variable has a default; templates render against whatever the merged config produces. We avoided `{{#if minister.X.enabled }}` blocks because they make the templates harder to read for everyone — orgs override the lists in `org-config.toml` and the rendered output reflects only what's enabled.

**No runtime substitution.** Templates are rendered once, at onboarding (or after `python -m ai_constitution render`). The output is plain TOML / Markdown that any agent runner can read. Re-render after a framework upgrade by re-running the renderer; we don't ship a template engine into your runtime.

**The mockability contract for sherpas:** every sherpa must support `--dry-run`. v0.0.1 has a known portability gap (the lifted sherpas reference raj-sadan filesystem paths) — see [CHANGELOG](CHANGELOG.md). v0.2 will close it via injected config.

---

## Why this exists (the long-form rationale)

A few decisions are worth defending in detail.

**Why constitution-as-code?** Most agent stacks treat governance as ad-hoc prompt scaffolding. That works for one project; it doesn't compose. Treating the constitution as code means you get version control, schema validation, automated tests, diff review, and the ability to upgrade the framework underneath an organization without rewriting their rules. The substrate (Python + jinja2 + TOML) is boring on purpose.

**Why parameterization at all?** The alternative is hand-forking. raj-sadan accumulated 222 mentions of "Mr. V", 61 of "Raj Sadan", 50 of "Vishal", 11 hardcoded ports, 8 service URLs across 18 files. Hand-forking that for a new org is realistic for one fork; it's not realistic for an ecosystem. The audit ([raj-sadan/audit/PARAMETERIZATION.md](https://github.com/vraj0703/raj-sadan)) walked through every substitution.

**Why one-shot render at onboarding rather than runtime substitution?** Two reasons. First: simplicity at the consumer side — no template engine in the runtime, no per-request rendering cost. Second: the rendered output is a plain artifact you can grep, edit by hand, and version-control. Runtime substitution couples every consumer to a template engine forever and makes the artifacts harder to debug.

**Why scoped variable namespace (`org.pm.name`) rather than flat (`PM_NAME`)?** It scales. Flat names work for ten variables; the registry has fifty and will grow. Dotted scoping mirrors TOML's table structure and lets us add `org.contacts.support_email` later without naming collisions.

**Why three repos rather than one or twelve?** One repo means consumers fork the whole thing to opt out of any minister or sherpa. Twelve repos (one per skill) means version-pinning hell. Three repos splits along the natural seams: framework / policy / execution. The collection repos (ai-ministers, ai-sherpa) hide individual-skill versioning behind a single submodule pin.

**Why Mustache-style `{{ org.x }}` rather than `${org.x}`?** Cloudflare's WAF flags `${...}` as injection in some contexts, and the dollar-brace form conflicts with future TOML-native env reference. Mustache is unambiguous and has parsers in every major language.

---

## Status & roadmap

| Milestone | Status | Linear |
|---|---|---|
| M1 — Audit & strategy | Done (in review) | [RAJ-45..50](https://linear.app/raj-sadan/project/ai-constitution) |
| M2 — Templates + render API | Done (in review) | RAJ-51..59 |
| M4 — Collection repos | Done (in review) | RAJ-60, 66..70 |
| M5 — Docs + v0.1.0 release | In progress | RAJ-71..75 |
| M6 — raj-sadan as consumer | Not started | RAJ-76..81 |
| M3 — Onboarding sherpa | Not started (last by design — it's the integration test) | RAJ-61..65 |

## Contributing

This is in active development. The Linear project at the link above tracks the roadmap. Issues welcome via GitHub.

## License

MIT.

## Credits

raj-sadan ([github.com/vraj0703](https://github.com/vraj0703)) is the reference implementation that ai-constitution was extracted from.
