Event-Sourced Task CLI

Every action is an immutable event. State is derived from projections over the event stream. Powered by AllSource, the embedded event database.

Rust 2024 Edition Event Sourced ~12us Reads
# Install from crates.io
$ cargo install chronis

# Initialize workspace
$ cn init

# Create your first task
$ cn task create "Design auth module" -p p0

Why Chronis?

Immutable Event Log Event Sourcing

Every mutation emits an event into Core's WAL. Full audit trail, time-travel debugging, and reproducible state from any point in history.

Microsecond Reads Core

TaskProjection folds events into a DashMap for ~12us concurrent reads. 469K events/sec write throughput with CRC32 integrity checks.

Full Durability Core

WAL with configurable fsync (default 100ms) and Parquet columnar storage with Snappy compression. Data survives crashes and restarts.

Task Hierarchy Core

Epics contain child tasks. Dependencies with blocking semantics. The cn ready command shows only unblocked, actionable work.

Agent Orchestration Event Sourcing

Set CN_AGENT_ID to coordinate multiple agents. First-write-wins claiming prevents conflicts. Every claim is an auditable event.

Interactive TUI UI

Full ratatui terminal interface with j/k navigation, Tab views, and c/d/a action keys. Or launch the embedded Axum + HTMX web viewer.

Git Sync Core

One command to stage, commit, and push your .chronis/ workspace. Tasks travel with your repository.

Beads Migration Event Sourcing

Import existing issues from .beads/ directories. Preserves history as creation events in the new event stream.

Zero Config Core

cn init creates a .chronis/ workspace. No external database, no daemon, no configuration file to edit. Just works.

Workflow

From backlog to shipped in four commands

cn ready
Find actionable work
cn claim <id>
Claim the task
(do work)
Write code
cn done <id>
Mark complete
cn sync --git
Push to remote

Commands

Command Alias Description
cn init Initialize a .chronis/ workspace
cn task create <title> Create a task with optional flags
cn list cn ls List tasks, optionally filtered by status
cn ready cn r Show open, unblocked tasks
cn show <id> cn s Task details, children, and event timeline
cn claim <id> cn c Claim a task (first-write-wins)
cn done <id> cn d Mark a task as done
cn approve <id> Approve a completed task
cn dep add <id> <blocker> Add a blocking dependency
cn dep remove <id> <blocker> Remove a blocking dependency
cn tui Interactive terminal UI
cn serve Embedded web viewer (Axum + HTMX)
cn sync --git Stage, commit, and push .chronis/
cn migrate-beads Import issues from .beads/ directory

Task Creation Flags

Fine-grained control over every task

$ cn task create "Title" \
  -p p1 \                # p0 (critical), p1, p2 (default), p3
  --type=epic \          # task, epic, bug, feature
  --parent=<id> \       # Parent task for hierarchy
  --blocked-by=<id> \   # Dependency
  -d "Description"      # Optional description

Best Practices

Git ignore rules and when to use TOON

Git Ignore for .chronis/

# Chronis (local event store data — sync exchange files are tracked)
.chronis/wal/
.chronis/storage/
.chronis/sync/.remote_ids
.chronis/sync/.local_ids
Path Contents Git? Why
.chronis/wal/ WAL segments (binary, CRC32) Ignore Machine-local binary data, causes merge conflicts
.chronis/storage/ Parquet files (binary, Snappy) Ignore Machine-local, rebuilt from WAL on startup
.chronis/sync/events.jsonl Append-only event log Track How cn sync shares events between machines
.chronis/sync/.remote_ids Imported event UUIDs Ignore Local dedup state, per-machine import cursor
.chronis/sync/.local_ids Exported event UUIDs Ignore Local dedup state, per-machine export cursor
.chronis/config.toml Workspace configuration Track Shared settings should be consistent across team
Ignore binary, track text. WAL and Parquet are binary formats that cause unsolvable merge conflicts. The JSONL sync file and config are text designed for git.

When to Use TOON

Use --toon when

  • AI agents consume the output (MCP tools, orchestration)
  • CI/CD pipelines parse task state
  • Piping to other tools (cut, awk, scripts)
  • Large task lists (50+ tasks) where token savings compound
  • Repeated polling (cn ready in a loop)

Don't use --toon when

  • A human is reading output in the terminal
  • Debugging task state with cn show
  • Taking screenshots or recording demos
  • Onboarding new team members
  • Using TUI (cn tui) or web viewer (cn serve)
If the consumer is an LLM or a script, use --toon. If the consumer is a human eyeball, don't.
# Agent workflow — always use --toon
$ export CN_AGENT_ID=agent-1
$ cn ready --toon
# → [id|type|title|pri|status|claimed|blocked_by|parent|archived]
# → t-abc1|task|Design auth module|p0|open||||false

$ cn claim t-abc1 --toon
# → ok:claimed:t-abc1

$ cn done t-abc1 --toon
# → ok:done:t-abc1

Full guide: BEST_PRACTICES.md

Architecture

cn CLI (clap)
    |
    v
TaskRepository trait
    |
    v
EmbeddedCore (allsource-core)
    |
    +--> WAL (CRC32, fsync) --> Parquet (Snappy)
    +--> DashMap (in-memory reads, ~12us)
    +--> TaskProjection (event folding)

Event Types

All state is derived from these immutable events

task.created cn task create
task.updated cn task update
task.dependency.added cn dep add
task.dependency.removed cn dep remove
workflow.claimed cn claim
workflow.step.completed cn done
workflow.approval.granted cn approve
~12us
Query Latency
469K
Events/sec Write
11
Integration Tests
0
External Dependencies

Get Started

Created by Decebal Dobrica. Part of the AllSource ecosystem. Install from crates.io and start managing tasks with immutable events.