Sillok
Sillok is a Rust CLI for meticulous agentic work chronicles. It records daily objectives, completed tasks, corrections, and retractions into a structured archive instead of a fragile append-only text log.
The name comes from Korean sillok, the court chronicles of Joseon. The design
goal is similar: keep precise records of what happened, when, under what
objective, and in what working context.
Status
Sillok is an early local-first CLI. The command interface is intended to be stable enough for agent harnesses. The live store is a private Turso/SQLite database and may gain new datashape versions over time.
Install
Build the binary in dev mode:
Install it onto your PATH:
Then use:
Storage
By default, Sillok stores one user-global Turso/SQLite database at:
$XDG_DATA_HOME/sillok/sillok.db
If XDG_DATA_HOME is unset, it falls back to:
~/.local/share/sillok/sillok.db
Override the store with either:
SILLOK_STORE=/path/to/sillok.db
The v2 store keeps append-only events plus indexed current projections in the database. Normal mutations insert a new event and update affected projection rows instead of loading and rewriting the whole chronicle.
Legacy v1 stores used a compressed private archive at sillok.slk.zst. Use
sillok migrate --store /path/to/sillok.slk.zst --target /path/to/sillok.db --yes
to create a v2 database. Migration always validates the legacy archive and
creates a timestamped backup before activating the target.
Git sync is archive-based, not database-based. The configured remote stores one
bitcode + zstd artifact, while every device keeps its own local SQLite/Turso
projection database. Sync config is stored beside the selected store at
<store>.sync.json.
Output
Quiet output is the default and is intended for agents. Successful write/action commands usually print nothing:
Read commands still return compact JSON data without the response envelope. Use
--json when an agent needs IDs or the full verbose response envelope:
Failures are compact JSON by default:
Use --json for verbose failure envelopes:
JSON records include stable RFC3339 created_at and updated_at fields.
Verbose success responses include ids, data, and warnings. Use --human
for interactive summaries with local-device timestamps rendered as readable
wall-clock time:
Functionality
Sillok supports:
- Local-first event logging into a SQLite/Turso projection store.
- Daily task notes with status, tags, purpose text, and parent links.
- Day objectives that can be created and completed with notes.
- Amendments and retractions that preserve event history.
- Day summaries, record history lookup, filtered queries, and task trees.
- Archive integrity validation.
- JSON export of current visible records.
- Legacy v1 archive migration into the v2 store.
- Explicit destructive truncation with timestamped backup.
- Git-backed sync of the authoritative event stream as one compressed artifact.
- Backfilled timestamps and timezone-controlled day attribution.
- Runtime work-context capture including cwd and Git metadata when available.
Command Reference
Global options:
Global option details:
--store: use a specific store path; defaults toSILLOK_STOREor XDG data storage.--human: print verbose readable summaries instead of quiet default output.--json: print the verbose JSON response envelope.--at: assign the event timestamp. Accepts RFC3339 or naiveYYYY-MM-DDTHH:MM:SS.--tz: timezone for local day attribution and naive--atparsing.SILLOK_ACTOR: optional actor label recorded on new events; defaults toagent.
Initialize the archive if absent:
Record a task or work note. Notes default to completed; use --status for
open, active, blocked, or completed:
note creates a task event. Without --parent, Sillok opens or reuses the day
record for the event timestamp and links the task under that day. With
--parent, the task is linked under an existing active record.
The status vocabulary is open, active, blocked, completed, and
retracted. Prefer sillok retract when hiding a record so the retraction
reason is preserved.
Manage day objectives:
Objectives are day-scoped records. Completing an objective changes its derived
status to completed; an optional completion note is stored on the record.
Amend current derived state:
amend records a new event and updates only the supplied fields in the current
projection. It requires at least one changed field.
Retract a task or objective from current views:
Retraction hides a task or objective from normal current views while preserving the underlying event history. Day records cannot be retracted.
Read records:
Read command behavior:
showreturns one current record plus every event that references it.dayreturns the selected day's tree, objectives, and visible non-day records. Omit--dateto use the current day in the selected timezone.queryreturns visible current records created in an inclusive time range. Filter by--context,--tag, or--status.treerenders the visible record tree rooted at--root, or at the selected day when--dateis supplied.
Validate and export:
doctor validates SQLite integrity and replays persisted events to confirm the
derived projection. export json returns visible current records; with
--from and --to, export is limited to records created in that inclusive
range.
Configure and run Git-backed event archive sync. Sync stores one
bitcode + zstd level 22 archive artifact in the configured Git remote; the
SQLite/Turso database remains local and is rebuilt from events when needed:
Sync command behavior:
sync remote set <URL>writes<store>.sync.json; defaults are branchmainand artifact pathsillok.slk.zst.sync remote showprints the configured URL, branch, artifact path, and sidecar path.sync pulloverwrites the local database with the remote archive (adopting itsarchive_id), keeping a timestamped backup of the old database. When the remote artifact is absent it is a no-op and leaves local state alone.sync pushoverwrites the remote artifact with the local archive. With no local archive it fails witharchive_missing.sync runis the merge path: it merges byevent_idwhen both sides share anarchive_id, rebuilds the local database with a backup, and pushes. When thearchive_ids differ it cannot merge — an interactive terminal is prompted to keep the local side (push) or the remote side (pull), while non-interactive runs (--jsonor no TTY) refuse withsync_mismatch_needs_choice.
Because each init mints its own archive_id, two independently-initialized
stores cannot merge directly. Bootstrap a second machine with sync pull once
(it adopts the remote archive_id); afterward both sides share an id and
sync run merges normally. Git authentication is delegated to the user's
existing git setup.
Migrate a legacy v1 archive:
migrate --dry-run validates the source archive and reports the migration plan.
Writing a v2 target requires --yes. If --target is omitted, Sillok writes
sillok.db beside the legacy archive.
Reset the archive only when an operator explicitly asks for a full reset. This creates a timestamped backup first:
truncate is destructive and requires --yes. It backs up the current v2
database, removes it, then initializes a fresh archive.
Backfill with explicit timestamps and timezone attribution:
RFC3339 timestamps keep their explicit offset. Naive timestamps are interpreted
in the selected --tz, or in the system-local timezone when --tz is omitted.
Agent Integration
Add a short Sillok section to a repository AGENTS.md so coding agents record
objectives and completed work while they operate:
Use Sillok for substantive agentic work. Record objectives, completed tasks,
and corrections during the session instead of relying on chat history. Quiet
output is the default for agents; use `--json` only when IDs or the full
response envelope are needed, and `--human` only for summaries intended for a
person.
Never run `sillok truncate --yes` unless the user explicitly asks to reset the
whole archive.
```bash
sillok objective add "Ship the storage/indexing refactor"
sillok note "Split reducer from view indexing" --parent <objective_id> --tags rust,sillok
sillok amend <record_id> --status completed
sillok note "Fixed relink regression coverage" --parent <objective_id> --tags tests
sillok show <record_id>
sillok query --from 2026-05-13T00:00:00 --to 2026-05-13T23:59:59 --tag rust
sillok objective complete <objective_id> --note "Scoped work is complete"
sillok day --human
```
Use `--at` for backfilled work and `--tz` when day attribution matters:
```bash
sillok --tz America/Denver --at 2026-05-13T16:45:00 note "Backfilled release notes" --tags docs
```
Development
Run checks:
Project constraints:
- No
unwrap()orexpect()in project source or tests. - Keep modules under 300 lines where practical.
- Keep folder
mod.rsfiles to module declarations only. - Prefer explicit error handling and structured tracing.
- Do not treat the live database or legacy archive serialization as a public standard; use CLI export/migration commands for compatibility.
Design Notes
See docs/plan/sillok-cli-chronicle-design.md for the initial implementation plan and data model notes. See docs/architecture/be/turso-store.md, docs/architecture/be/view-indexing.md, and docs/architecture/be/git-sync.md for backend architecture notes.