Skip to content

chitinhq/chitin

Repository files navigation

Chitin

Runtime governance engine for AI coding agents. Chitin intercepts tool calls from agent drivers (Claude Code, GitHub Copilot, Codex, Gemini), normalizes them into six canonical action types, evaluates them against deny-first policy rules and safety invariants, and emits allow/deny decisions back to the driver.

Architecture

flowchart LR
    A[Agent Driver] -->|tool call| B[Hook]
    B -->|parse env vars| C[Normalize]
    C -->|Action| D[Invariant Check]
    D -->|violations?| E[Policy Evaluate]
    E -->|Decision| F{Allow / Deny}
    F -->|allow| G[exit 0]
    F -->|deny| H[exit 2 + JSON]
Loading

Hook (internal/hook/) -- Reads tool call data from driver-specific environment variables (CLAUDE_HOOK_EVENT_NAME, COPILOT_HOOK_EVENT, etc.) and dispatches to the evaluation pipeline. Read-only actions are fail-open; missing policy files are fail-closed.

Normalize (internal/normalize/) -- Maps each tool call to one of six canonical ActionType values: read, write, exec, git, net, dangerous. Uses the canon package to parse shell commands and classify by tool, flags, and patterns.

Invariant Check (internal/invariant/) -- Runs registered safety invariants before policy evaluation. Invariants cannot be overridden by policy rules; they can only be set to monitor (warn) or off per invariant in chitin.yaml. Built-in invariants include recursive-delete guard, permission escalation detection, network egress restriction, IDE socket access prevention, destructive SQL detection, and dynamic script execution tracking.

Policy Evaluate (internal/policy/) -- Two-phase evaluation against chitin.yaml rules. Phase 1: any matching deny rule blocks (deny always wins). Phase 2: any matching allow rule permits. Phase 3: no match means default deny (fail-closed). Policy mode can be enforce (block) or monitor (warn only).

Event Emit (internal/hook/emit.go) -- Appends every governance decision as a JSON line to .chitin/events.jsonl for telemetry ingestion.

Getting Started

Prerequisites

  • Go 1.18+
  • An AI coding agent: Claude Code, GitHub Copilot, OpenAI Codex, or Google Gemini

Install

From source:

go install github.com/chitinhq/chitin/cmd/chitin@latest

Or via the install script:

curl -fsSL https://raw.githubusercontent.com/chitinhq/chitin/main/install.sh | bash

Quick Start

Initialize hooks and a starter policy for your agent driver:

chitin init claude     # or: copilot, codex, gemini

This writes three files:

  • .claude/settings.json (or equivalent for your driver) -- hooks config
  • chitin.yaml -- starter policy with deny rules for dangerous ops, protected branches, and secrets
  • .chitin-identity -- agent identity file

Check that everything is wired up:

chitin status

Test how a specific action would be evaluated without executing it:

chitin evaluate -t Bash -c "rm -rf /tmp/data"
# Tool:     Bash
# Action:   dangerous
# Decision: DENY
# Reason:   Dangerous operations require human approval
chitin evaluate -t Bash -c "git status"
# Tool:     Bash
# Action:   git
# Decision: ALLOW

Validate a policy file:

chitin validate chitin.yaml

Policy File

Policies are defined in chitin.yaml at the project root:

mode: enforce  # or "monitor" (warn without blocking)

rules:
  - action: dangerous
    effect: deny
    reason: Dangerous operations require human approval

  - action: git
    branches: [main, master]
    effect: deny
    reason: Direct push to protected branch

  - action: write
    target: ".env"
    effect: deny
    reason: Secrets files must not be modified by agents

  - action: "*"
    effect: allow
    reason: Default allow for non-restricted actions

invariantModes:
  no-network-egress: monitor    # warn but don't block
  script-execution-tracking: off # disable this check

Action types for rules: read, write, exec, git, net, dangerous, *.

Public Packages

canon

github.com/chitinhq/chitin/canon -- Shell command canonicalization with equivalence digests. Parses raw shell strings into structured, normalized forms. Semantically equivalent commands produce identical digests.

package main

import (
    "fmt"
    "github.com/chitinhq/chitin/canon"
)

func main() {
    // Equivalent commands produce the same canonical form and digest.
    cat := canon.ParseOne("cat foo.txt")
    head := canon.ParseOne("head foo.txt")
    fmt.Println(cat.Tool)   // "read"
    fmt.Println(head.Tool)  // "read"
    fmt.Println(cat.Digest == head.Digest) // true

    // Tool aliases, flag normalization, and subcommand extraction.
    cmd := canon.ParseOne("rg -n pattern src/")
    fmt.Println(cmd.Tool)   // "grep"
    fmt.Println(cmd.Args)   // [pattern src/]

    // Pipeline parsing with chain operators.
    pipeline := canon.Parse("git add . && git commit -m 'fix'")
    fmt.Println(len(pipeline.Segments)) // 2
    fmt.Println(pipeline.Segments[1].Op) // "&&"

    // Sensitive values are automatically masked.
    secret := canon.ParseOne("curl -H 'Authorization: Bearer sk-longtoken1234567890abcdefghij' http://api.example.com")
    // Long token-like args replaced with [MASKED]
}

Features:

  • 60+ tool aliases (e.g., cat/head/tail -> read, rg/ag/ack -> grep)
  • Short-to-long flag normalization (-r -> recursive, -i -> ignore-case)
  • Deterministic SHA256 digests (first 16 hex chars) for deduplication
  • Chain and pipe parsing (&&, ||, ;, |)
  • Automatic masking of secrets and API keys in arguments

Development

# Build
go build ./cmd/chitin

# Run tests
go test ./...

# Run tests for a specific package
go test ./canon/

# Vet
go vet ./...

License

See LICENSE.

About

Runtime governance for AI coding agents — lean kernel, single binary, 26 invariants

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors