Skip to content

aaronsb/agent-ways

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,433 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Agent Ways logo — a W made of nodes and edges with a red-to-green gradient representing attention falloff, emerging from a dim background knowledge graph

Agent Ways

GitHub stars GitHub forks GitHub issues License Last commit

Organizational socialization for AI coding agents. Ways encode "the way we do it around here" — the local norms an agent cannot know because it was never told them — and deliver them the way human teams actually transmit norms: situated, at the moment of relevant action, just before tools execute.

An LLM session cannot internalize norms — no weight updates, no carried memory; every session is a new hire. So the system re-enacts socialization mechanically, on a spaced schedule that substitutes for the memory the agent does not have. In one sentence: procedural memory for coding agents, maintained by spaced repetition. Every project-coined term here maps to an established concept — the vocabulary reference is the index.

Current status: Agent Ways ships with full support for Claude Code. Support for additional CLI-based coding agents is in development.

⚠️ Breaking change in 1.0 — existing installs must migrate. Before 1.0, the repo was your install (~/.claude was the clone). 1.0 turns ~/.claude into a thin projection of an XDG application whose source lives in $XDG_DATA_HOME/agent-ways. A pre-1.0 in-place clone moves over with one gated, backup-first command — ways migrate --execute — after upgrading (cd ~/.claude && git pull && make update). Your projects/ and settings.json are preserved. The migrator is transitional: it ships through the 1.2.x line and is removed in 1.3, after which migrating means checking out a pre-1.3 release first. See the Migration Guide.

sequenceDiagram
    participant U as 👤 You
    participant C as 🤖 Agent
    participant W as ⚡ Ways

    rect rgba(21, 101, 192, 0.2)
        U->>C: "fix the auth bug"
        W-->>C: 🔑 Security · 🐛 Debugging
    end
    rect rgba(106, 27, 154, 0.2)
        C->>W: about to run: git commit
        W-->>C: 📝 Commit format rules
    end
    rect rgba(0, 105, 92, 0.2)
        C->>W: spawning subagent
        W-->>C: 🔑 Security (injected into subagent too)
    end
    rect rgba(198, 40, 40, 0.15)
        Note over U,W: Context fills up → auto-compact → ways reset → cycle repeats
    end
Loading

Ways = policy and process encoded as contextual guidance. Triggered by keywords, commands, and file patterns — they fire before tools execute, re-disclose on a token-distance cadence as their influence fades, and carry into subagents.

Why this works: System prompt adherence decays as a power law over conversation turns — instructions at position zero lose influence as context grows. This is the forgetting curve (Ebbinghaus) operating over token distance instead of days, and the countermeasure is the one human learning already uses: spaced repetition. Ways inject small, relevant guidance near the attention cursor at the moment it matters and re-disclose it as its influence fades, maintaining steady-state adherence instead of a damped sawtooth. It's progressive disclosure applied to the model itself.

Session replay with ways rethink

ways rethink replays a completed session's way-firing history as an interactive TUI animation. Each frame shows a way firing at a specific point in the conversation — you can see how guidance clusters near the active attention cursor and packs into the context window like a compression pattern.

ways rethink replaying a session — each frame shows a way firing, guidance clusters near the attention cursor and packs like a compression pattern as context fills

Ways fire via the embedding engine (all-MiniLM-L6-v2, a ~21MB GGUF model), which achieves ~98% accuracy on the match fixture set. The embedding tier handles semantic similarity — "pin lockfile versions" matches the supply chain way even though those exact words don't appear in the way's vocabulary.


This repo ships with software development ways, but the mechanism is general-purpose. You could have ways for:

  • Excel/Office productivity
  • AWS operations
  • Financial analysis
  • Research workflows
  • Anything with patterns your agent should know about

Prerequisites

Runs on Linux and macOS. The core system is a Rust binary (ways) plus thin bash hook scripts:

Tool Purpose Notes
Claude Code The agent this configures npm install -g @anthropic-ai/claude-code
ways Unified CLI — matching, scanning, linting, governance Downloaded or built by make setup
git Version control, update checking Usually pre-installed
jq JSON parsing (hook inputs, configs, API responses) Must install
python3 Governance traceability tooling, chart-tool Stdlib only — no pip packages
gh GitHub API (update checks, repo macros) Recommended, not required — degrades gracefully

make setup acquires the ways binary automatically: pre-built download from GitHub Releases → build from source (requires cargo/Rust toolchain) → error with instructions. Standard utilities (bash, awk, sed, grep, find, timeout, tr, sort, wc, date) are assumed present via coreutils.

Semantic matching uses the embedding engine (all-MiniLM-L6-v2 via a separate way-embed binary, ~98% accuracy on the fixture set) as the sole retrieval tier. The embedding model is a hard dependency of ways and is fetched by make setup:

make setup   # download ways binary + embedding model (~21MB), generate corpus

See Semantic Matching for the full setup and engine comparison.

Platform install guides: macOS (Homebrew) · Arch Linux · Debian / Ubuntu · Fedora / RHEL

macOS note: timeout is a GNU coreutils command not present by default. Install coreutils via Homebrew — see the macOS guide for PATH setup.

Quick Start

curl -sL https://raw.githubusercontent.com/aaronsb/agent-ways/main/scripts/install.sh | bash -s -- --bootstrap

This stages the app into $XDG_DATA_HOME/agent-ways, builds the binaries and fetches the embedding model (~21MB), links the CLIs onto your PATH, and runs ways reconcile to project the framework into ~/.claude. In 1.0, ~/.claude is a thin projection — so your existing config (sessions, credentials, settings.json, projects/) is preserved, not replaced: the install only adds symlinks for the projected roots and merges the hooks block into your settings. Restart Claude Code and the ways are active.

The built-in ways cover software development, but the framework is domain-agnostic. To customize, fork it and pass your fork to the installer, or set up a development checkout — then replace the ways and add your own domains. For non-straightforward installs (existing forks, offline, custom prefixes), see the install guide.

Upgrading a pre-1.0 in-place clone (where ~/.claude is the git repo)? Don't git pull it — run the gated, backup-first migrator after upgrading: ways migrate --execute. Your projects/ and settings.json are preserved. See the Migration Guide.

Stop and read this if you're letting an AI agent run the installer. You are about to let an agent modify ~/.claude/ — the directory that controls how Claude Code behaves. The agent is editing its own configuration. Review the repo first. You are responsible for the result.

How It Works

core.md loads at session start with behavioral guidance, operational rules, and a dynamic ways index. Then, as you work:

  1. UserPromptSubmit scans your message for keyword and semantic (embedding) matches
  2. PreToolUse intercepts commands and file edits before they execute
  3. SubagentStart injects relevant ways into subagents spawned via Task
  4. A way fires when matched, then re-discloses on its refire: cadence (a fraction of the context window, ADR-126) as its salience decays — marker files track the first fire and drive that re-disclosure state machine, they don't permanently block re-triggering

Matching has two channels: regex patterns for known keywords/commands/files, and sentence-embedding semantic scoring (all-MiniLM-L6-v2). See matching.md for the full strategy.

ways list shows the live session state — which ways fired, when (epoch), how far back (distance), what triggered them, tree relationships, check decay curves, and a re-disclosure forecast showing when distant ways will re-fire as context fills:

ways list showing live session state — epoch when each way fired, distance in context, colored pins for attention proximity, tree disclosure, and a forecast of when distant ways will re-fire

For the complete system guide — trigger flow, state machines, the pipeline from principle to implementation — see docs/hooks-and-ways/README.md.

Configuration

User config lives in $XDG_CONFIG_HOME/agent-ways/config.yaml (YAML). For example, to disable whole domains:

disabled_domains:
  - itops

A legacy ~/.claude/ways.json ({"disabled": [...]}) is still honored as a lower-precedence layer for un-migrated installs.

Key Purpose
disabled_domains List of domain names to skip (e.g., [itops, softwaredev]) — in legacy ways.json this key is disabled

Disabled domains are completely ignored — no pattern matching, no output.

Creating Ways

Each way is a {wayname}.md file with YAML frontmatter in ~/.claude/hooks/ways/{domain}/{wayname}/:

---
description: semantic text    # embedding semantic matching (preferred)
vocabulary: domain keywords   # space-separated terms augmenting the embedding
pattern: commit|push          # regex on user prompts (supplementary)
commands: git\ commit         # regex on bash commands
files: \.env$                 # regex on file paths
macro: prepend                # dynamic context via macro.sh
scope: agent, subagent        # injection scope
---

Matching has two independent lanes. A way fires when the semantic probability g(s) clears the global threshold τ_s, or when a pattern:/commands:/files: regex matches and g(s) clears the lower keyword floor τ_k. The keyword lane is floor-gated — a regex hit can't drag in an unrelated prompt — except it fails open when no calibration is loaded, and pattern_strict: true bypasses the gate by design. See the engine reference for the exact fire rule.

Project-local ways live in $PROJECT/.claude/ways/{domain}/{wayname}/{wayname}.md and override global ways with the same path. Project macros are disabled by default — trust a project with echo "/path/to/project" >> ~/.claude/trusted-project-macros.

For the full authoring guide: extending.md | For matching strategy: matching.md | For macros: macros.md

Testing Ways

After creating or tuning a way, verify it matches what you expect — and doesn't match what it shouldn't.

# Score a way against sample prompts (inside Claude Code)
/ways-tests score security "how do i hash passwords with bcrypt"

# Rank all ways against a prompt
/ways-tests score-all "write some unit tests for this module"

# Validate frontmatter
ways lint --global

# Vocabulary gap analysis
ways suggest --file ~/.claude/hooks/ways/softwaredev/code/security/security.md

# Embedding similarity scores
way-embed match --corpus ~/.cache/agent-ways/user/ways-corpus.jsonl \
  --model ~/.cache/agent-ways/user/minilm-l6-v2.gguf \
  --query "pin lockfile versions"

# Sibling vocabulary overlap (Jaccard)
ways siblings softwaredev/code/supplychain/depscan/node

# Session simulation tests (Rust integration tests)
make test-sim

# Interactive: full hook pipeline with subagent injection
# Start a fresh session, then: read and run tests/way-activation-test.md

The embedding engine achieves 98.4% accuracy (63/64) with 0 false negatives on the fixture set.

Other test tools: scripts/doc-graph.sh --stats checks documentation link integrity; ways-audit lint validates provenance metadata. Full test guide: tests/README.md.

What's Included

This repo ships with 85+ ways across six domains — covering commits, security, testing, debugging, dependencies, architecture, documentation, and more. The live index is generated at session start. Replace these entirely if your domain isn't software dev.

Domain Ways Coverage
softwaredev 50 Commits, security, testing, debugging, deps, supply chain, architecture, delivery
meta 19 Ways system itself — knowledge, authoring, optimization, introspection
ea 10 Executive assistant — email, calendar, scheduling
itops 4 Infrastructure operations
research 1 Research workflows
writing 1 Writing and documentation

Also included:

  • Agent teams — three-scope model (agent/teammate/subagent) with scope-gated governance and team telemetry. When one agent becomes a team, every teammate gets the same handbook.
  • 6 specialized subagents for requirements, architecture, planning, review, workflow, and organization
  • Usage stats — way firing telemetry by scope, team, project, and trigger type
  • Update checking — detects clones, forks, renamed copies; nudges you when behind upstream

Why Ways? (Rules, Skills, and Ways)

Claude Code ships two official features for injecting guidance: Rules (.claude/rules/*.md) and Skills (~/.claude/skills/). Ways solve problems that neither can.

The problem has a name in principal–agent theory: preference uncertainty. An agent that doesn't know its principal's norms has only two safe strategies — ask constantly, or hedge exhaustively. Remove the ways system and agents of every model tier revert to exactly that. Rules and skills each supply some norms; ways supply them situated — at the moment of action, wherever in the file tree that action happens.

The progressive disclosure problem

Rules and ways both inject guidance conditionally — but their disclosure models are fundamentally different:

  • Rules disclose based on file paths (paths: src/api/**). The project's directory tree is the disclosure taxonomy. This works when concerns map cleanly to directories, but most concerns don't — security, testing conventions, commit standards, and performance patterns cut across every directory.

  • Ways disclose based on actions and intent — what you're doing (running git commit), what you're talking about ("optimize this query"), or what state the session is in (context 75% full). The disclosure schedule is decoupled from the file hierarchy entirely.

This matters because of how attention works in transformers. Rules loaded at file-read time are closer to the generation cursor than startup rules, but ways inject at the tool-call boundary — the closest possible point to where the model is actively generating. The context decay model formalizes why this temporal coupling outperforms spatial coupling for maintaining adherence over long sessions.

Three features, three jobs

Rules Skills Ways
What Static instructions Action templates Event-driven guidance
Job "Always do X" "Here's how to do Y" "Right now, remember Z"
Trigger File access or startup User intent (Claude decides) Tool use, keywords, state conditions
Conditional on File paths (directory tree) Semantic similarity Multi-channel: regex, embeddings, commands, files, state
Cross-cutting concerns Needs duplicate paths: entries N/A (intent-based) Single way fires regardless of file location
Dynamic content No No Yes (shell macros)
Survives refactoring No (src/lib/ breaks paths) Yes Yes
Non-file triggers No No Yes (git commit, context threshold, subagent spawn)
Compliance claims No No Yes (design claims → NIST, OWASP, ISO, SOC 2)
Org-level scope Yes (/etc/claude-code/) No No
Zero-config simplicity Yes (drop a .md file) Yes No (requires hook infrastructure)

Rules are best for static, always-on preferences ("use TypeScript strict mode", "tabs not spaces"). Skills are best for specific capabilities invoked by intent ("ship this PR", "rotate AWS keys"). Ways are best for context-sensitive guidance that fires on events, cuts across the file tree, and needs to stay fresh in long sessions.

They compose well: rules set baseline preferences, ways inject guidance at tool boundaries, skills provide specific workflows. The full comparison covers the architectural details.

Is this just RAG? Ways and RAG solve the same fundamental problem — getting the right context into the window at the right time — but through different architectures. RAG retrieves by semantic similarity; Ways retrieve by event. RAG is stateless; Ways track session state. The full comparison explores what's shared, what's different, and when each approach wins.

Governance

A way can carry a compliance claim: a provenance.yaml sidecar linking it to policy documents and the regulatory controls its guidance is designed to address. The runtime never reads it (zero tokens), but the governance operator walks the chain:

Control Framework → Policy Document → Way + claim → Agent Context

The governance/ directory contains reporting tools and policy source documents — claim-coverage queries, control traces, matrices. Designed to be separable. The built-in ways carry justification claims across controls from NIST, OWASP, ISO, SOC 2, CIS, and IEEE — assertions about how the guidance is designed, not evidence that any control operates.

Most users don't need it. It's an additive layer that helps work take a control-aligned shape at the point of work: a first-line aid, not an assessment or attestation. Read any coverage number as claims made, not conformance achieved. See docs/governance.md for the full reference.

For adding a claim: provenance.md | Design rationale: ADR-200

Philosophy

Policy-as-code for AI agents — lightweight, portable, deterministic.

Feature Why It Matters
Dual-channel matching Regex for precision, embeddings for semantics — no cloud API needed
Shell macros Dynamic context from any source (APIs, files, system state)
Minimal dependencies ways binary + bash + jq — no runtime services, no cloud APIs
Domain-agnostic Swap software dev ways for finance, ops, research, anything
Fully hackable Plain text files, fork and customize in minutes

For the attention mechanics: context-decay.md | For the cognitive science rationale: rationale.md

Updating

In 1.0 the app source lives in $XDG_DATA_HOME/agent-ways (not ~/.claude). Update by refreshing that checkout, then rebuilding and reprojecting — or just re-run the installer one-liner, which is idempotent:

cd "$XDG_DATA_HOME/agent-ways" && make update && ways reconcile

make update pulls (robustly — it autostashes around machine-local settings drift), force-rebuilds the binaries, regenerates the corpus, and relinks; ways reconcile then refreshes the ~/.claude projection. Use make update, not make setupsetup skips binaries that already exist, so on an update it would leave you on the old binary. A fork fetches and merges upstream in the app dir first (git fetch upstream && git merge upstream/main), then make update-binaries && ways reconcile (force-rebuild without re-pulling origin; the corpus self-heals via the SessionStart hook).

At session start, check-config-updates.sh flags when you're behind upstream (aaronsb/agent-ways), rate-limited to once per hour. It currently recognizes legacy git-based layouts — an in-place clone at ~/.claude, and the ADR-140 subdirectory (.claude-source marker). Native-projection update detection is being wired (it reads the app source in $XDG_DATA); until then, use the manual command above.

Scenario How detected Sync command
Native projection (1.0) app source at $XDG_DATA_HOME/agent-ways cd "$XDG_DATA_HOME/agent-ways" && make update && ways reconcile
Fork GitHub API reports parent is aaronsb/agent-ways fetch/merge upstream in the app dir, then make update-binaries && ways reconcile
Legacy in-place clone ~/.claude is itself the git repo ways migrate --execute first (moves it to the projection model)
Plugin CLAUDE_PLUGIN_ROOT set with plugin.json /plugin update disciplined-methodology

Renamed clones (org-internal copies)

If your organization clones this repo under a different name without forking on GitHub, update notifications still work via the .claude-upstream marker file. It uses git ls-remote against the public upstream — no gh CLI required.

Goal Action
Opt out entirely Delete .claude-upstream and point origin to your internal repo.
Track a different upstream Edit .claude-upstream to contain your internal canonical repo.
Disable for all users Remove check-config-updates.sh from hooks/ or delete the SessionStart hook entry in settings.json.

Documentation

Path What's there
docs/vocabulary.md The framing — terminology anchors, why "ways", the canonical description
docs/hooks-and-ways/README.md Start here — the pipeline, creating ways, reading order
docs/hooks-and-ways/ Matching, macros, provenance, teams, stats
docs/hooks-and-ways.md Reference: hook lifecycle, state management, data flow
docs/governance.md Reference: compilation chain, provenance mechanics
docs/architecture.md System architecture diagrams
docs/architecture/ Architecture Decision Records
governance/ Governance traceability and reporting
docs/README.md Full documentation map

License

MIT

About

No description, website, or topics provided.

Resources

License

Code of conduct

Contributing

Security policy

Stars

19 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors