- Rust 81%
- Racket 15.9%
- Shell 1.9%
- Python 1.1%
hence
A CLI tool for multi-agent LLM plan coordination using defeasible logic.
Install
From Binary (recommended)
Download and install the standalone binary (no dependencies required):
curl -fsSL https://files.anuna.io/hence/latest/install.sh | bash
This installs to ~/.local/bin by default. To install elsewhere:
INSTALL_DIR=/usr/local/bin LIB_DIR=/usr/local/lib curl -fsSL https://files.anuna.io/hence/latest/install.sh | bash
Manual Binary Install
- Download the archive for your platform from releases
- Extract:
tar -xzf hence-*.tar.gz - The extracted directory contains both
bin/andlib/- both are needed - Copy preserving structure:
# Install to ~/.local (binary looks for ../lib relative to itself) cp -r hence-dist/bin/hence ~/.local/bin/hence cp -r hence-dist/lib/plt ~/.local/lib/
LLM agents generate plans in Spindle Lisp (SPL) format. This tool reasons about next steps, assignments, and completion. Multiple agents query the same plan and accumulate facts as work progresses.
Plans can be local files or hosted on hence.run for multi-agent coordination across machines.
Architecture
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ LLM Agent │ │ LLM Agent │ │ LLM Agent │
│ (claude) │ │ (codex) │ │ (gemini) │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└────────────────┼────────────────┘
│
┌────────────┴────────────┐
│ │
▼ ▼
┌─────────────────┐ ┌───────────────────┐
│ hence CLI │ │ hence agent spawn │
│ task next/done │ │ (PTY + worktree) │
│ task claim/assert│ └────────┬──────────┘
└────────┬────────┘ │
│ ┌────────┴──────────┐
│ │ hence agent watch │
│ │ (auto-spawn loop) │
│ └────────┬───────────┘
│ │
├───────────────────────┘
│
├── hooks/ (lifecycle scripts)
├── validators/ (custom validation)
├── hence-* (external commands)
├── config.toml (providers, settings)
│
┌─┴───────────┬─────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌──────────┐ ┌──────────────┐
│ plan.spl │ │hence.run │ │ spindle-core │
│ (local file)│ │ (hosted) │ │(DFL reasoner)│
└─────────────┘ └──────────┘ └──────┬───────┘
│
▼
conclusions (+D, +d)
Local files work for single-machine use. hence.run enables multi-agent coordination across machines with ~32k simultaneous agents per plan.
Installation (from source)
Requires Racket (8.x or later).
# Clone the repository
git clone https://codeberg.org/anuna/hence.git
cd hence
# Install Racket dependencies (spindle and crypto)
raco pkg install --auto
# Option 1: Build standalone distribution (no Racket needed at runtime)
make distribute
./hence-dist/bin/hence --help
# Option 2: Build for development (requires Racket at runtime)
make build
./hence --help
To install system-wide:
# Standalone install (no Racket required to run)
sudo make install-dist
# Or development install (requires Racket)
sudo make install
Install to a custom location:
make install-dist PREFIX=~/.local
Usage
# What should happen next?
hence task next plan.spl
# Filter by agent (show only their assignments)
hence task next plan.spl --agent coder
# JSON output for programmatic use
hence task next plan.spl --json
# Who should handle what?
hence task assign plan.spl
# Mark task complete (adds fact, re-reasons)
hence task complete models plan.spl
# Claim a task (mark in-progress, prevents other agents from taking it)
hence task claim auth plan.spl
# Block a task (adds defeater rule to prevent assignment)
hence task block auth "waiting for API keys" plan.spl
# Unblock a task (removes block fact and defeater rule)
hence task unblock auth plan.spl
# Assert a discovery (fact, rule, defeater, or superiority)
hence task assert '(given discovered-issue)' plan.spl --agent coder
hence task assert '(normally r1 found-bug needs-fix)' plan.spl --agent coder
# Spawn an agent to work a task (auto-selects ready task)
hence agent spawn plan.spl --agent claude
# Spawn a specific task
hence agent spawn plan.spl --agent codex --task auth
# Watch plan and auto-spawn agents for ready tasks
hence agent watch plan.spl --spawn --agent claude
# Watch with a task limit
hence agent watch plan.spl --spawn --agent claude --max-tasks 5
# Why was this concluded?
hence query explain ready-crud plan.spl
# Why was this NOT concluded?
hence query why-not ready-tests plan.spl
# Inspect a rule, fact, or literal (show definition and meta)
hence query describe plan.spl r-ready-auth
hence query describe plan.spl r-ready-auth task-models --json
# What facts are needed? (abductive reasoning)
hence query require ready-tests plan.spl
# Show defeaters and rule annotations
hence query require ready-tests plan.spl -v
# Assume facts when reasoning backwards (abductive)
hence query require ready-tests plan.spl --assume completed-auth
# JSON output for LLM consumption
hence query require ready-tests plan.spl --format json
# Show all conclusions
hence plan status plan.spl
# Kanban board view
hence plan board plan.spl
# Verbose board with dependencies and block reasons
hence plan board plan.spl --verbose
# Dry-run spawn (assemble context without launching agent)
hence agent spawn plan.spl --agent claude --dry-run
# Stream NDJSON events to a file
hence agent spawn plan.spl --agent claude --events events.ndjson
# Watch with session tracking and events
hence agent watch plan.spl --spawn --agent claude --session my-run --events events.ndjson
# Translate a markdown spec into an SPL plan
hence plan translate spec.md --agent claude -o plan.spl
# Review a plan for issues and ambiguities
hence plan review plan.spl --agent claude
# Decompose a task into subtasks (abduction-guided LLM expansion)
hence plan decompose auth plan.spl --agent claude
# Decompose and merge subtasks directly into the parent plan
hence plan decompose auth plan.spl --agent claude --merge
# Decompose with JSON output for programmatic use
hence plan decompose auth plan.spl --agent claude --json
# List all sessions
hence sessions
# Show session details
hence session my-run
# Spindle Lisp format reference for LLMs (default)
hence llm
# DFL format reference for LLMs
hence llm dfl
Commands
hence plan -- Plan Management
| Command | Description |
|---|---|
hence plan init |
Initialize a new plan |
hence plan validate <file> |
Check plan syntax |
hence plan info <file> |
Show plan metadata |
hence plan status <file> [--json] |
Show all conclusions |
hence plan board <file> [--agent NAME] [-v] [--json] [--format FMT] |
Kanban board view of task states |
hence plan summary <file> |
Show plan summary |
hence plan translate <spec> [--agent NAME] [-o FILE] [--context CTX] |
Translate a markdown specification into an SPL plan via headless agent |
hence plan decompose <task> [file] [--agent NAME] [-o FILE] [--merge] [--json] |
Decompose a task into subtasks using abduction-guided LLM expansion |
hence plan review <file> [--agent NAME] [--context CTX] [--json] |
Review a plan for issues and ambiguities via headless agent |
hence task -- Task Operations
| Command | Description |
|---|---|
hence task next <file> [--agent NAME] [--json] |
Show next actions based on current state |
hence task assign <file> [--agent NAME] [--json] |
Show agent assignments |
hence task complete <task> [file] |
Add completion fact, re-reason (validates task exists) |
hence task claim <task> [file] |
Mark task in-progress (prevents other agents from taking it) |
hence task unclaim <task> [file] |
Release a claimed task |
hence task block <task> <reason> [file] |
Block task with annotated defeater rule |
hence task unblock <task> [file] |
Remove block fact and defeater rule |
hence task assert <spl> [file] [--agent NAME] [--task NAME] |
Assert discovery with full DSL power |
hence agent -- Agent Spawn & Watch
| Command | Description |
|---|---|
hence agent spawn <file> --agent <name> |
Spawn an agent to execute a ready task in an isolated worktree |
hence agent watch <file> [--spawn --agent <name>] |
Watch plan for state changes, optionally auto-spawning agents |
hence agent whoami |
Show the current agent identity |
hence agent spawn handles the full lifecycle: claim task, create git worktree, assemble context prompt, launch agent via PTY, evaluate results, merge back. Supports 21 built-in agent CLIs (claude, codex, qwen, gemini, cursor, copilot, amp, and more) plus custom providers via config.toml.
| Flag | Command | Description |
|---|---|---|
--task <name> |
spawn | Execute a specific task instead of auto-selecting |
--cleanup |
spawn, watch | Remove worktree after completion |
--no-merge |
spawn | Skip merging task branch into integration branch |
--show-prompt |
spawn | Print assembled context prompt to stderr |
--token-budget <n> |
spawn | Token budget for context assembly |
--max-tasks <n> |
watch | Exit after spawning N tasks |
--delay <secs> |
watch | Polling interval (default 5s) |
--dry-run |
spawn, watch | Assemble context without launching agent |
--events <path> |
spawn, watch | Emit NDJSON events to file or - for stdout |
--session <name> |
spawn, watch | Tag events with a session name (requires --events) |
--pool |
watch | Enable worktree pool pre-allocation |
--trust-plan-checks |
spawn | Trust evaluate-checks from plan meta (remote plans) |
--lease-ttl <dur> |
spawn | Lease TTL as ISO 8601 duration (default: PT30M) |
--idle-timeout <dur> |
spawn | Idle timeout as ISO 8601 duration (default: PT5M) |
--timeout <dur> |
spawn | Wall-clock timeout as ISO 8601 duration (default: PT60M) |
--json |
watch | Output state changes as JSON |
hence remote -- Hence.run (Remote Plans)
| Command | Description |
|---|---|
hence remote new [file.spl] |
Create hosted plan on hence.run (optionally from local file) |
hence remote cp <src> [dst] |
Copy between local and remote |
hence remote ls |
List your hosted plans |
hence remote rm <url> |
Archive a hosted plan |
All commands work with URLs:
# Create hosted plan
hence remote new plan.spl
# → https://hence.run/p/abc123
# Use remote plan (same commands as local)
hence task next https://hence.run/p/abc123
hence task complete design https://hence.run/p/abc123
hence plan board https://hence.run/p/abc123
# Download remote plan
hence remote cp https://hence.run/p/abc123 local.spl
hence query -- Explanation & Reasoning
| Command | Description |
|---|---|
hence query explain <literal> [file] |
Show derivation chain with semantic annotations |
hence query why-not <literal> [file] |
Explain why not concluded (DL(d) proof condition analysis) |
hence query describe <file> <labels...> [--json] |
Inspect rules/facts/literals - show definitions and meta |
hence query require <literal> [file] [-v] [--assume FACTS] [--format json] |
Abductive reasoning with defeater analysis |
hence query what-if <file> <facts...> [--json] |
Hypothetical reasoning - show new conclusions if facts were added |
hence query trace <file> |
Full reasoning trace with all derivations |
Describe Command Details
The hence query describe command inspects rules, facts, and literals in a plan:
- Rules: Shows the full rule definition and all meta annotations
- Facts: Shows the fact declaration
- Derived literals: Shows which rules derive the literal
# Inspect a single rule with its meta
hence query describe plan.spl r-ready-auth
# Inspect multiple items at once
hence query describe plan.spl r-ready-auth task-models ready-api
# JSON output for programmatic use
hence query describe plan.spl r-ready-auth --json
Example output:
Label: r-ready-auth
Rule:
(normally r-ready-auth
(and task-auth no-deps-auth)
ready-auth)
Meta:
description: Auth task becomes ready when dependencies met
acceptance: Auth should be assignable
JSON output structure:
{
"label": "r-ready-auth",
"type": "rule",
"rules": [
{
"label": "r-ready-auth",
"body": "(and task-auth no-deps-auth)",
"head": "ready-auth",
"kind": "defeasible",
"meta": {
"description": "Auth task becomes ready when dependencies met",
"acceptance": "Auth should be assignable"
}
}
]
}
Abductive Planning Details
The hence query require command performs abductive reasoning to find what facts would make a goal provable:
- Multiple paths: When multiple rule chains can derive the goal, all paths are shown
- Defeater analysis: Shows what defeaters could block each path (e.g.,
¬readyblocksr1) - Rule provenance: Shows which rules fire in each derivation chain (
Via rules: r1, r2) - Common facts: When multiple paths exist, highlights facts common to all paths
Flags:
| Flag | Description |
|---|---|
-v, --verbose |
Show rule annotations (description, source, etc.) |
--assume FACTS |
Assume facts when reasoning backwards (comma-separated or repeated) |
--format json |
Output as JSON for LLM consumption |
JSON output structure:
{
"goal": "deployed",
"already_provable": false,
"paths": [
{
"facts": ["tested", "approved"],
"via_rules": ["r1", "r2"],
"defeated_by": [{"defeater": "¬ready", "blocks": "r1"}]
}
],
"common_facts": ["tested"]
}
Hypothetical Reasoning (What-If)
The hence query what-if command performs hypothetical reasoning - showing what new conclusions would become derivable if specified facts were added:
# What if we completed models?
hence query what-if plan.spl completed-models
# What if we completed multiple tasks?
hence query what-if plan.spl completed-models completed-auth
# JSON output for programmatic use
hence query what-if plan.spl completed-models --json
Example output:
═══════════════════════════════════════════════════════════════
What-If Analysis
═══════════════════════════════════════════════════════════════
Hypothetical facts:
+ completed-models
───────────────────────────────────────────────────────────────
NEW conclusions (would become derivable):
+d ready-crud
+d assign-crud-coder
───────────────────────────────────────────────────────────────
Summary: 8 original conclusions → 10 total conclusions (2 new)
hence learn -- Process Mining
| Command | Description |
|---|---|
hence learn extract-log <files...> [--format json|summary] |
Extract event log from completed plan traces |
hence learn rules <files...> [--format dfl|json|summary] |
Mine rules from plan execution history |
hence learn validate-rules <traces...> --against <file> |
Compare learned rules against existing plan |
Top-Level Commands
| Command | Description |
|---|---|
hence llm |
Spindle Lisp format reference for LLMs (default) |
hence llm spl |
Spindle Lisp format reference |
hence llm dfl |
DFL format reference |
hence sessions [--json] |
List all sessions with status and timestamps |
hence session <name> [--json] |
Show session details and task states |
hence skill init |
Install Claude Code skill (.claude/skills/hence/SKILL.md) |
hence repl |
Interactive REPL |
hence completions |
Shell completions |
Plan Format (Spindle Lisp)
LLM agents generate plans in Spindle Lisp (SPL) format. SPL supports both propositional atoms and first-order predicates with Datalog-style variable grounding.
;; Facts: current state
(given task-models)
(given task-auth)
(given agent-coder-available)
(given agent-security-available)
(given security-related-auth)
(given no-deps-models)
;; Strict rules: invariants (cannot be defeated)
(always r1 (and goal requires-security) needs-review)
;; Defeasible rules: defaults (can be overridden)
(normally r10 (and task-models agent-coder-available) assign-models-coder)
(normally r11 (and task-auth agent-coder-available) assign-auth-coder)
(normally r12 (and task-auth security-related-auth agent-security-available) assign-auth-security)
;; Task readiness (based on dependencies)
(normally r20 (and task-models no-deps-models) ready-models)
(normally r21 (and task-crud completed-models) ready-crud)
;; Superiority: conflict resolution
(prefer r12 r11) ; security beats coder for auth task
SPL Constructs
| Construct | Syntax | Meaning |
|---|---|---|
| Fact | (given literal) |
Asserts something is true |
| Relational fact | (given (pred arg1 arg2)) |
Asserts a relation |
| Strict rule | (always r1 (and A B) C) |
If A and B, then C (cannot be defeated) |
| Defeasible rule | (normally r1 (and A B) C) |
If A and B, then typically C (can be overridden) |
| Defeater | (except d1 A (not C)) |
If A, then block conclusion C |
| Superiority | (prefer r2 r1) |
Rule r2 wins over r1 in conflicts |
| Negation | (not literal) |
Negated literal |
| Variable | ?x, ?y |
Datalog-style variables (automatically grounded) |
First-Order Variables
SPL supports variables with automatic Datalog-style grounding:
;; Relational facts
(given (parent alice bob))
(given (parent bob charlie))
;; Rule with variables - automatically grounded
(normally r1 (parent ?x ?y) (ancestor ?x ?y))
(normally r2 (and (parent ?x ?y) (ancestor ?y ?z)) (ancestor ?x ?z))
Claims with Attribution
Track who asserted what and when:
(claims agent:security
:at "2026年01月21日T09:00:00Z"
:note "Security scan results"
(given scan-complete)
(given no-critical-vulns)
(normally sec1 scan-complete scanned))
Metadata
Annotate rules for explainability:
(meta r20
(description "Security-sensitive tasks require security agent")
(source "policy/security-guidelines.md")
(confidence 0.95))
(normally r20 (and ready-auth security-sensitive agent-security) assign-auth-security)
Metadata appears in hence query explain output.
Modular Plans
Import conclusions from other files:
(import "./agents.spl")
(import "./common.spl")
This allows splitting plans into reusable modules (e.g., agent definitions, common rules).
Discoveries
Agents can assert discoveries during execution using hence task assert. Discoveries support full SPL power: facts, rules, defeaters, and superiority relations.
# Assert a fact
hence task assert '(given discovered-api-deprecated)' plan.spl --agent coder
# Assert a rule that reacts to discoveries
hence task assert '(normally r1 discovered-issue needs-review)' plan.spl --agent coder
# Assert a defeater to block a task
hence task assert '(except d1 found-vulnerability (not ready-deploy))' plan.spl --agent security
Naming Conventions
Use prefixes for discoverability and cross-agent coordination:
| Prefix | Purpose | Example |
|---|---|---|
discovered- |
Findings during execution | discovered-api-deprecated |
decided- |
Design decisions made | decided-use-redis |
blocked-by- |
Blockers identified | blocked-by-missing-credentials |
requires- |
Prerequisites found | requires-api-key |
verified- |
Validations passed | verified-authentication-works |
failed- |
Failures observed | failed-integration-test |
Blocker/Unblocker Pattern
Facts (given) cannot be defeated. To create blockers that can be unblocked, use an intermediate derived literal:
;; Use intermediate literal that CAN be defeated
(normally r-has-vulnerability discovered-vulnerability has-active-vulnerability)
(except d-block has-active-vulnerability (not ready-deploy))
(except d-unblock verified-fix (not has-active-vulnerability))
This preserves the discovery as an audit trail while allowing its effect to be defeated.
Timestamps
All mutation commands (hence task complete, hence task claim, hence task block, hence task unblock, hence task assert) automatically add ISO8601 timestamps via claims blocks. This enables:
- Process mining: Extract temporal patterns from execution history
- Audit trails: Track when each discovery was made
- Ordering: Ensure events sort correctly for analysis
(claims system
:at "2026年01月17日T14:30:00Z"
(given completed-auth))
Concurrency Safety
All mutations (hence task complete, hence task claim, hence task block, hence task unblock, hence task assert) are append-only. This enables safe concurrent writes from multiple agents without locks or coordination.
POSIX guarantees atomic writes up to 4096 bytes when appending to a file. Hence discoveries are designed to stay well under this limit, so simultaneous writes from different agents will not interleave or corrupt each other.
Agent A: hence task complete auth plan.dfl ─┐
Agent B: hence task assert '...' plan.dfl ─┼─► All appends preserved
Agent C: hence task claim deploy plan.dfl ─┘
The plan file serves as a simple append-only log. Each command re-reads and re-reasons from the full file, so agents always see a consistent view of accumulated facts.
The ordering of facts and rules in the file does not matter—the defeasible logic engine reasons over the entire theory at once. Conclusions depend only on what is asserted, not when or where it appears in the file.
Process Mining
Learn plan patterns from execution history. Process mining extracts event logs from completed plans and discovers rules that explain observed behavior.
Note: Process mining requires timestamped facts. All mutation commands (hence task complete, hence task claim, hence task block, hence task unblock, hence task assert) automatically add timestamps. For initial plan facts without timestamps, the earliest timestamp in the file is used as fallback.
Extract Event Log
Convert completed plans into a structured event log:
# Extract events from multiple plan files
hence learn extract-log plans/*.spl --format json > events.json
# View summary
hence learn extract-log plans/*.spl --format summary
# Event Log Summary
# =================
# Cases: 3
# Total events: 24
#
# Case: plans/sprint-1.dfl (8 events)
# 1: completed_auth {task: auth}
# 2: completed_models {task: models}
# ...
Learn Rules
Mine defeasible rules from execution traces:
# Output learned rules as DFL
hence learn rules plans/*.spl --format dfl
# ---
# description: "Learned from 3 traces (support: 3, confidence: 1.00)"
# ---
# r_learned_1: completed_models => ready_crud
# View mining summary
hence learn rules plans/*.spl --format summary
# Mining Results
# ==============
# Traces: 3
# Rules learned: 5
# Conflicts detected: 1
# Choice points: 2
Validate Against Existing Rules
Compare learned patterns against your plan template:
hence learn validate-rules plans/*.spl --against template.spl
# Validation Report
# =================
# Traces analyzed: 3
# Rules learned: 5
# Existing rules: 12
#
# Coverage:
# Already covered: 4 rules
# New patterns: 1 rules
#
# Conflicts:
# ✗ Learned rule conflicts with existing r12
# Learned: completed_auth => ready_deploy
# Existing: completed_auth, security_approved => ready_deploy
This helps identify:
- New patterns: Rules observed in practice but missing from the template
- Conflicts: Learned behavior that contradicts existing rules
- Low confidence rules: Patterns that vary across traces (may need defeaters)
Conclusions
+D literal- Definitely provable (from strict rules/facts)+d literal- Defeasibly provable (from defeasible rules, not defeated)-D literal- Definitely not provable-d literal- Defeasibly not provable
Example Session
$ hence plan board examples/api-project.spl -v
┌──────────────┬──────────────┬──────────────┬──────────────┬──────────────┐
│ BACKLOG │ READY │ IN PROGRESS │ BLOCKED │ DONE │
├──────────────┼──────────────┼──────────────┼──────────────┼──────────────┤
│tests │models @coder │ │ │ │
│crud │auth @security│ │ │ │
│review │ │ │ │ │
└──────────────┴──────────────┴──────────────┴──────────────┴──────────────┘
Tasks: 3 backlog, 2 ready, 0 in-progress, 0 blocked, 0 done
BACKLOG (waiting on):
tests - needs: crud, auth
crud - needs: models
review - needs: tests
ASSIGNMENTS:
models → coder
auth → security
$ hence task next examples/api-project.spl
Next actions:
1. assign-models-coder
2. assign-auth-security
$ hence task complete models examples/api-project.spl
Added: (given completed-models)
Next actions:
1. assign-crud-coder
2. assign-auth-security
$ hence task block crud "waiting for DB schema" examples/api-project.spl
Added: (given blocked-crud)
Added: (except d-blocked-crud blocked-crud (not ready-crud)) ; reason: waiting for DB schema
Next actions:
1. assign-auth-security
$ hence query describe examples/api-project.spl r42
Label: r42
Rule:
(normally r42
(and task-crud completed-models)
ready-crud)
Meta:
description: CRUD task ready after models complete
$ hence query why-not ready-crud examples/api-project.spl
═══════════════════════════════════════════════════════════════
Why not: ready-crud
═══════════════════════════════════════════════════════════════
To prove +∂ ready-crud, these conditions must hold:
(1) Definitely provable (+Δ): ✗
Not definitely provable
→ Checking defeasible proof path...
(2) Negation not definitely provable (-Δ ¬q): ✓
No strict rule derives ¬ready-crud
(3) Applicable rule exists: ✓
Rule r42 is applicable
(4) All competing rules defeated: ✗
Undefeated competitor: d-blocked-crud
Competing rules for ¬ready-crud:
✗ d-blocked-crud: blocked-crud ~> ¬ready-crud
Status: APPLICABLE and NOT DEFEATED
Description: Task crud is blocked
Justification: waiting for DB schema
═══ FAILURE POINT ═══
A defeater is blocking this conclusion.
═══ SUGGESTIONS ═══
1. Add superiority: r42 > d-blocked-crud
2. Defeat the competing rule's prerequisites
$ hence task unblock crud examples/api-project.spl
Removed: (given blocked-crud)
Removed: (except d-blocked-crud blocked-crud (not ready-crud))
Next actions:
1. assign-crud-coder
2. assign-auth-security
$ hence query require ready-tests examples/api-project.spl
═══════════════════════════════════════════════════════════════
Requirements for: ready-tests
═══════════════════════════════════════════════════════════════
To make ready-tests provable:
Path 1 (2 facts needed):
(given completed-crud)
(given completed-auth)
Via rules: r43
$ hence query require ready-tests examples/api-project.spl --assume completed-auth
═══════════════════════════════════════════════════════════════
Requirements for: ready-tests
Assuming (already true): completed-auth
═══════════════════════════════════════════════════════════════
To make ready-tests provable:
Path 1 (1 fact needed):
(given completed-crud)
Via rules: r43
$ hence learn extract-log plans/sprint-*.spl --format summary
Event Log Summary
=================
Cases: 3
Total events: 24
Case: sprint-1.spl (8 events)
2026年01月15日T09:00:00Z: completed {task: models}
2026年01月15日T10:30:00Z: completed {task: auth}
2026年01月15日T14:00:00Z: completed {task: crud}
...
$ hence learn rules plans/sprint-*.spl --format summary
Mining Results
==============
Traces: 3
Rules learned: 5
Conflicts detected: 0
Choice points: 1
Learned Rules:
(normally _ completed-models ready-crud) (support: 3, confidence: 1.00)
(normally _ (and completed-crud completed-auth) ready-tests) (support: 3, confidence: 1.00)
For LLM Agents
When generating a plan:
- Start with facts describing the goal and context
- Add facts for available agents
- Decompose into task facts
- Mark tasks with no dependencies using
no-deps-<task>facts - Add strict rules for invariants
- Add defeasible rules for assignments (only for ready tasks)
- Add defeasible rules for readiness based on completed dependencies
- Add superiority relations to resolve conflicts
When working on a plan manually:
# Get the format reference
hence llm | claude -p
# Create a hosted plan for multi-agent coordination
hence remote new plan.spl
# → https://hence.run/p/abc123
- Query
hence task next <plan> --agent <name> --jsonto see available work - Claim work with
hence task claim <task> <plan>(prevents other agents from taking it) - Assert discoveries as you work:
hence task assert '<spl>' <plan> --agent <name> - Complete work and run
hence task complete <task> <plan> - If a task is too large, decompose it:
hence plan decompose <task> <plan> --agent <name> --merge - If blocked, run
hence task block <task> <reason> <plan> - To unblock, run
hence task unblock <task> <plan> - Re-query to see what's next
Or use hence agent spawn to automate the full lifecycle:
# Spawn one agent to work the next ready task
hence agent spawn plan.spl --agent claude
# Watch and auto-spawn agents as tasks become ready
hence agent watch plan.spl --spawn --agent claude
hence agent spawn handles claiming, worktree isolation, context assembly, agent launch, evaluation, and merging -- no manual coordination needed.
Where <plan> is either a local file (plan.spl) or a hence.run URL (https://hence.run/p/...).
Discoveries accumulate in the plan and are visible to all agents. Use the naming conventions (discovered-, verified-, blocked-by-, etc.) for cross-agent coordination.
Sessions & Events
Track plan execution across spawn/watch runs with sessions and structured event streaming.
Sessions
Sessions record plan execution state in a local SQLite store (~/.hence/sessions.db):
# Start a session when spawning
hence agent watch plan.spl --spawn --agent claude --session sprint-1 --events events.ndjson
# List all sessions
hence sessions
# Show session details with task progress
hence session sprint-1
NDJSON Event Streaming
Stream structured events during spawn/watch for observability and tooling integration:
hence agent spawn plan.spl --agent claude --events events.ndjson
hence agent spawn plan.spl --agent claude --events - # stdout
Events include: spawn_start, worktree_created, context_assembled, agent_started, agent_exited, evaluation_complete, spawn_complete, watch_start, cycle_start, state_change, watch_complete, and more.
Each event is a JSON object with event, timestamp, plan, task, agent, and event-specific data.
Agent Supervision
hence agent spawn includes a supervision layer that separates execution from recovery. Inspired by BEAM/OTP's supervisor model, three roles with distinct cryptographic identities manage different concerns:
| Role | Identity | Responsibility |
|---|---|---|
| Supervisor | supervisor:{pubkey} |
Holds time-bounded lease, monitors agent liveness, renews or revokes claims |
| Agent | agent:{pubkey} |
Performs task work in the worktree; no plan writes |
| Evaluator | evaluator:{pubkey} |
Assesses output quality and correctness |
No single entity holds all three powers — the agent cannot claim its own work is complete, the supervisor cannot assess quality, and the evaluator cannot extend a lease.
Lease-Based Claims
Task claims use (during ...) temporal bounds so they expire naturally if the supervisor crashes. The reasoner filters expired leases at reference_time: now — no central lease server or coordinator process required.
Liveness Monitoring
The supervisor passively observes agent activity through PTY output and worktree file modifications. If no activity is observed within the idle timeout, it asserts stale-v{N}-{task} which defeats the active claim via defeasible logic. A wall-clock timeout provides an outer bound even for agents that produce output continuously but make no useful progress.
Configuration
All supervision parameters follow the precedence: plan metadata > CLI flag > default.
| Parameter | CLI Flag | Plan Metadata | Default |
|---|---|---|---|
| Lease TTL | --lease-ttl |
(meta task (id "X") (lease-ttl "PT30M")) |
30 min |
| Idle timeout | --idle-timeout |
(meta task (id "X") (idle-timeout "PT5M")) |
5 min |
| Wall-clock timeout | --timeout |
(meta task (id "X") (timeout "PT60M")) |
60 min |
| Max retries | — | (meta task (id "X") (max-retries 2)) |
2 retries (3 total attempts) |
# Spawn with custom timeouts
hence agent spawn plan.spl --agent claude --idle-timeout PT10M --timeout PT2H
# Per-task configuration in the plan
(meta task (id "heavy-refactor") (timeout "PT2H") (idle-timeout "PT10M") (max-retries 3))
Failure Propagation
When a task fails, goes stale, or times out, downstream dependents are concluded as upstream-blocked-{task} via defeasible rules. Propagation is transitive — if A fails and B depends on A and C depends on B, both B and C become upstream-blocked.
After exhausting all retries (default: 2), a task is marked permanently-failed-{task} — a terminal state that also propagates downstream.
Status Integration
hence plan status and hence plan board display supervision state when present:
$ hence plan status plan.spl
Task supervision:
auth -> in-progress (attempt 2/3, stale: v1, lease active)
impl -> upstream-blocked (blocked by: auth [stale-v1])
api -> upstream-blocked (blocked by: impl [upstream-blocked])
Plugins
Hence supports git-style plugin extensibility. No source modifications or recompilation required.
External Commands
Any executable named hence-{name} in your PATH becomes a subcommand:
# Create a plugin
echo '#!/bin/sh
echo "Hello from hence-hello!"' > ~/.local/bin/hence-hello
chmod +x ~/.local/bin/hence-hello
# Use it
hence hello # → "Hello from hence-hello!"
hence hello --flag # args are passed through
Built-in commands always take precedence over external commands.
Configuration
TOML configuration at ~/.hence/config.toml (global) and .hence/config.toml (project-local). Local values override global.
[settings]
hook_timeout = 30 # seconds before killing a hook (default: 30)
plugin_path = [] # additional directories to search for plugins
# Custom agent providers for spawn/watch
[[providers]]
id = "myagent"
name = "My Custom Agent"
cli = "myagent-cli"
initial_prompt_flag = "-p"
auto_approve_flag = "--yes"
Custom providers are available to hence agent spawn and hence agent watch via (meta task-X (provider "myagent")) in plan files.
# Worktree file provisioning (symlink or copy files into agent worktrees)
[worktree.provision]
files = [
{ from = ".env", to = ".env", mode = "copy" },
{ from = "config/shared.toml", to = "config/shared.toml" }, # default: symlink
]
Lifecycle Hooks
Executable scripts in ~/.hence/hooks/ or .hence/hooks/ run after lifecycle events:
| Hook | Triggered after |
|---|---|
post-claim |
hence task claim |
post-complete |
hence task complete |
post-block |
hence task block |
post-unblock |
hence task unblock |
post-assert |
hence task assert |
post-plan-complete |
All tasks in plan completed |
Hooks receive <plan-file> <task> <agent> as arguments and environment variables HENCE_HOOK, HENCE_PLAN, HENCE_TASK, HENCE_AGENT, HENCE_EVENT. Hook failures produce warnings but never affect the primary operation.
# Example: Slack notification on task completion
cat > .hence/hooks/post-complete << 'EOF'
#!/bin/sh
curl -s -X POST "$SLACK_WEBHOOK" \
-d "{\"text\": \"Task 2ドル completed by 3ドル in 1ドル\"}"
EOF
chmod +x .hence/hooks/post-complete
Custom Validators
Executable scripts in ~/.hence/validators/ or .hence/validators/ run during hence plan validate. They receive the plan file path as 1ドル and output JSON diagnostics to stdout:
[
{"level": "warning", "message": "Task auth has no description"},
{"level": "error", "message": "Missing agent availability fact", "line": 42}
]
In --strict mode, custom validator warnings become errors.
Board Formatter Plugins
Custom output formats for hence plan board via the --format flag:
# Built-in formats: json, kanban, tree, dag
hence plan board plan.spl --format json
# External formatter: hence-board-{format} receives board JSON on stdin
hence plan board plan.spl --format html # invokes hence-board-html
Environment Variables
User-facing
| Variable | Description |
|---|---|
HENCE_AGENT |
Default agent name. Used as fallback when --agent is not passed. Equivalent to adding --agent <name> to every command. |
NO_COLOR |
Disable colored output when set to any non-empty value. Follows the no-color.org convention. Equivalent to --no-color. |
HENCE_DEBUG |
Enable verbose debug logging to stderr when set to 1. |
# Set once, used by all commands
export HENCE_AGENT=coder
hence next plan.spl # same as: hence next plan.spl --agent coder
# Disable color in CI or piped output
export NO_COLOR=1
hence board plan.spl
# Debug logging
HENCE_DEBUG=1 hence spawn plan.spl --agent claude
Hook and validator environment
These variables are set by hence when executing lifecycle hooks and custom validators:
| Variable | Description |
|---|---|
HENCE_PLAN |
Absolute path to the plan file |
HENCE_TASK |
Task name (hooks only) |
HENCE_AGENT |
Agent name (hooks only) |
HENCE_HOOK |
Hook name, e.g. post-complete (hooks only) |
HENCE_EVENT |
Event type (hooks only) |
HENCE_STRICT |
"true" or "false" (validators only) |
Directories
Hence follows XDG Base Directory defaults:
| Variable | Default | Used for |
|---|---|---|
XDG_CONFIG_HOME |
~/.config |
Identity and remote plan metadata ($XDG_CONFIG_HOME/hence/) |
XDG_DATA_HOME |
~/.local/share |
Plan replicas ($XDG_DATA_HOME/hence/) |
Hooks, validators, and config.toml use a separate directory at ~/.hence/ (global) and .hence/ (project-local).
License
AGPL-3.0