Getting started

This page takes about ten minutes. It describes ljos 0.35.0. Items marked “coming in 0.35.0” are not in 0.34.1.

By the end you will have remembered a lesson and put two seats on one ticket. They will have voted, noted and settled the vote. You will have asked ljos-policyd about a command, and you will know how to take ljos off again.

0. Install#

$ curl -fsSLO https://github.com/leidarljos/ljos/releases/latest/download/install.sh && sh install.sh
$ export PATH="$HOME/.local/bin:$PATH"

The programs go to ~/.local/bin. They are ljos, ljos-mcp, packset, packsetd, vissue, deedar, claimdag, ljos-policyd and ljos-consensus. The installer checks each download against its published SHA-256 sum. It builds from source with cargo where a platform has no release. --no-embed leaves out the encoder for meaning-based search.

Read the script before you run it. It is scripts/install.sh in this repository. It runs ljos onboard for each coding agent it finds. With none found, it still sets up the tracker, the pack writer and the deed store.

To install by hand, or to see what onboarding would write:

$ cargo binstall --locked ljos packset deedar-cli claimdag-cli vissue-cli vissue-mcp ljos-policyd ljos-consensus
$ ljos onboard --dry-run
$ ljos onboard
$ ljos doctor

ljos onboard writes the MCP entry, the hooks and the skill into each runner it finds. ljos onboard --example lists the runners ljos knows. ljos doctor prints only the rows that need action. Add --all to see every row.

Nothing needs a variable set. ljos onboard makes a deed store, a tracker and a config file for vissue, and it starts the pack writer. Git needs an identity, because the tracker commits each change.

Codex runs a hook only after you trust it. Open /hooks in Codex and trust each ljos hook. Trust it again after an upgrade rewrites one.

1. The memory loop#

$ ljos remember "The lexical default is BM25+. It beat BM25 by two points on turns."
$ ljos prefer "CombMNZ over RRF for fusing two ballots."
$ ljos search "which fusion"
2.0000  1/3 lesson  1fe4b916d956798196df680ade594ac5    today   The lexical default is BM25+. It beat BM25 by two points on turns.
1.0000  1/3 preference  85dde12b553372dafb3d50e3b4b63fec    today   CombMNZ over RRF for fusing two ballots.

A claim is two sentences at most, and it is stored as written. A lesson or a preference you type takes effect at once. The hook shows both from the next prompt they bear on. Run ljos remember from a terminal of your own. An agent that runs it writes an unreviewed note, which the prompt does not treat as a fact.

Tomorrow, ljos due lists both claims. Read each one and grade it:

$ ljos graded 3f9c...            # recalled: comes back later
$ ljos graded 3f9c... --lapsed   # had to look it up: comes back sooner

A claim you stop reviewing sinks in search. A claim shown wrong is retired with the deed that showed it: ljos forget 3f9c... --why deed-....

2. Two seats on one ticket#

A seat is one agent working the tracker. Name each seat with LJOS_SEAT. The tracker needs a project, so the first ticket creates one.

$ ljos file "Pick a codec" -p demo -t decision --options keep,drop
demo-fhy7  TODO  [#C]  Pick a codec
file: .../tracker/Software/demo/issues.org
tracker git: committed chore(issues): demo-fhy7 filed by alice; no remote, kept local
$ ljos claim demo-fhy7 --assignee alice
gen=2
tracker: demo-fhy7 STARTED under alice

One seat holds a ticket at a time. If bob claims it now, the claim is refused and the refusal names alice. Bob files or claims another ticket. To help on this one, bob writes a note or sends alice a message.

Both seats vote, each from its own runner. A seat votes once on a ticket. ljos refuses a second ballot from one shell, whatever session id the second ballot names.

$ ljos vote demo-fhy7 --for keep --used none     # in alice's runner
$ ljos vote demo-fhy7 --for keep --used none     # in bob's runner
$ ljos consensus demo-fhy7 --no-file
settle (DeGroot, 2 voters): keep 1.000
every voter is on keep: the settle is unanimous
polarization 0.000, disagreement 0.000
influence: alice 0.500, bob 0.500

ljos consensus reads the trust rows in the pack. It settles the votes with the consensus crate. With no rows, every voter weighs the same. --no-file makes the command read only. Without it, a blocking objection with a reason is filed on the ticket.

Now the seats leave notes and read each other’s.

$ ljos note demo-fhy7 "the codec is one file"    # in alice's runner
$ ljos recall demo-fhy7                          # in bob's runner
...
Memory
  unverified logbook notes:
  - [unverified agent note (origin agent-derived), today, from alice] alice: the codec is one file

ljos recall prints the working set for a ticket: the plan, the deeds it cites, and the notes. Notes are unverified text written by whoever wrote them. Read them as data.

To see what happened across the seats, use ljos digest. It is coming in 0.35.0.

$ ljos digest

ljos digest reads the tracker and says what each seat filed, claimed, voted on, noted and finished. Until then, read the same facts one at a time:

$ ljos timeline demo-fhy7      # one ticket, oldest first
$ ljos claims                  # who holds what
$ ljos log --seat alice        # one seat's tracker commits

Agreement that learns#

Suppose the vote was split and the world picked a side.

$ ljos learn demo-xxxx --outcome drop
Learned. 2 trust rows rewritten. ...
alice weighs bob at 1.000
bob weighs alice at 1.000

By default learn weighs each voter by its hits and misses across outcomes. One outcome cannot tell a lucky voter from a good one, so the rows stay level. They separate as more tickets get an outcome. With --rule hedge, only the voters the outcome refuted shrink:

$ ljos learn demo-xxxx --outcome drop --rule hedge
alice weighs bob at 1.000
bob weighs alice at 0.500

The rows are trust atoms in the pack. They carry a validity window, a later row replaces an earlier one, and they travel in a handover. A person can set one by hand: ljos trust alice bob 0.9 --why deed-....

Finish#

$ echo 'fn main() {}' > codec.rs
$ deedar create file --name "the codec" --path codec.rs --agent alice
$ ljos deed demo-fhy7 --add deed-file-the-codec
$ ljos finish demo-fhy7 --assignee alice --lesson "The codec is one file." --outcome keep
completed the session node for demo-fhy7 as done
tracker: demo-fhy7 no longer claimed by alice; back to TODO
proposed 081ce739... as agent-derived; `ljos accept 081ce739...` writes it
the ticket demo-fhy7 stays open and nobody holds it; a person closes it when the work is accepted

ljos finish hands the claim back and proposes the lesson. The lesson stays out of the pack until you run ljos accept ID in your own terminal. Completing a claim node does not close the ticket. A person does, when the work is accepted.

3. Seats and grants#

Coming in 0.35.0. The tracker’s vissue.toml lists the seats. Add one with:

$ ljos seat add carol

ljos seat add writes the seat’s row in vissue.toml. You no longer edit the file by hand. ljos seat prints the name this agent works under and where the name came from. The name is LJOS_SEAT when it is set. Otherwise ljos derives one from the runner, and a derived name counts as a seat.

A grant with close=own lets one named seat close the tickets it filed or has claimed. It is coming in 0.35.0. Without a grant, ljos finish leaves the ticket open for a person to close.

$ ljos seat grant alice close=own --quote "the person's words" --at 2026-10-29T02:00:00Z --via RECORDER

The row lives in vissue.toml. It holds the quote, the time, the recorder named by --via, and the tracker commit. A grant edited in by hand is ignored. A seat cannot grant itself. Every close cites the grant record.

Solo mode#

Coming in 0.35.0. When vissue.toml lists one active seat, that seat’s own vote settles consensus for the push check. With two or more seats, the normal quorum applies.

4. Ask policyd#

ljos-policyd reads each shell command before it runs. ljos policy -- COMMAND prints its answer for one command and runs nothing.

$ ljos policy -- ls
ls
allow
$ ljos policy -- rm -rf /usr/share/foo
rm -rf /usr/share/foo
deny: rm-rf-outside-tmp: a recursive delete outside /tmp cannot be undone. ...

There are four answers. allow runs the command. ask shows the runner’s permission prompt, and you answer it. deny stops the command and names the rule. rewrite is coming in 0.35.0. It replaces the command with a fixed one and lets that one run. The answer is allow, rewrite and the new command, separated by tabs. Each rewrite leaves a note and a row in $XDG_DATA_HOME/ljos/rewrite.jsonl. A repository’s rewrite = false turns rewriting off there.

A force push to main, master, develop or a protected branch asks. An ordinary push of a branch runs. A push onto a protected branch also asks when the ticket of your sitting has no settled consensus. With one active seat, its own vote settles it.

If ljos-policyd is missing or slow, the command runs and ljos logs a warning. ljos doctor shows the policy row.

5. Hand a ticket to another seat#

$ ljos handover --out /tmp/bag --issue demo-fhy7
issues=1 deeds=1 files=8
/tmp/bag/manifest-sha256.txt.sig

On the receiving seat, with its own stores:

$ ljos receive /tmp/bag
the payload matches the manifest ...
$ ljos receive /tmp/bag --import

The receiver checks three things in order. The bag arrived as written. The deeds were in the sender’s log before the handover. A key the receiver accepts signed it. Only then does it import the atoms and the trust rows.

A scratch seat has no host key, so its bag goes out unsigned, and --import refuses an unsigned bag. ljos onboard writes the key.

6. Take it off#

Coming in 0.35.0:

$ ljos offboard

ljos offboard undoes what ljos onboard wrote. It removes the ljos entries from each runner’s files and leaves the rest of each file as it was.

scripts/fresh-install-check.sh tests the whole path. It installs into an empty HOME, onboards, and takes two seats through file, claim, vote, consensus, note, recall and digest. Then it runs ljos offboard and checks that HOME is clean. It lists every step that failed.

$ scripts/fresh-install-check.sh --cargo-target target/release

Where next#

  • How-to: wire the server into a runner, sign handovers, read the cards.

  • Reference: every verb and tool.

  • Explanation: why it is built this way.