ljos

io.github.leidarljos由 GitHub 账号 leidarljos 发布v0.39.0更新于 Nov 7, 2026

Local memory, a work tracker and a shell-command guard shared by coding runners on one machine.

概览

AI 生成的概览

本地 MCP 服务器,为编码代理提供共享记忆、基于 git 的工单跟踪(含席位与投票)以及 shell 命令防护。

可以做什么
  • 存储与检索记忆:按原文写入规则和偏好,搜索并在提示前呈现相关条目
  • 跟踪工作:创建工单、开启 sitting、认领与释放工单、记录笔记、回顾并以经验结束
  • 协作决策:对选项投票、结算共识,并查看各席位行为的摘要
  • 检查 shell 命令:向策略守护进程询问命令是否危险,得到放行、警告或改写结果
  • 交接与消息:向其他席位发送文本、读取收件箱、回复,并交接签名包
  • 运行诊断:检查哪个已安装组件无响应
适用场景
当多个编码代理或会话在同一台机器上处理同一批仓库,且你希望共享工单、跨会话保留有意的记忆,并在破坏性 shell 命令前获得警告时使用。它适合想要“谁决定了什么”记录的人,而不是当作沙箱。
运行要求
需在 Linux 或 macOS 本地安装(Windows 仅通过 WSL,未测试);安装脚本把程序放入 ~/.local/bin,或用 cargo 从源码编译,需 Rust 1.89 或更新版本。onboarding 会向它找到的每个编码运行器写入 MCP 条目、钩子和技能。可选环境变量包括用于命名席位的 LJOS_SEAT,以及跳过转录读取的 LJOS_EXTRACT=off。
安装前请注意
shell 防护只发出警告:递归删除、强制推送、读取凭据文件等危险命令仍会执行,且明确不是沙箱。钩子在失败时放行,策略守护进程缺失或缓慢时命令照常运行。onboarding 会写入运行器配置文件和一个工单仓库,后者可能被之后的 git add 提交。可选的托管模型默认关闭,一旦配置会把提示和候选记忆发送到本机之外。

安装

在 SourceWeft 中

  1. 打开 控制台中的 ljos,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

ljos

Claude Code, Codex, Cursor and other coding runners work on one person's repositories. A new session does not keep the last session's lessons. Two agents can claim the same work. Nobody can see who decided what.

ljos is the record of who decided what: memory you write on purpose, a git-backed ticket tracker that agents share, and a warner for shell commands.

You install it once on a machine. Each agent gets a seat on a tracker. The tracker is a git repository of tickets. A seat files a ticket and opens a sitting on it. A sitting claims that ticket and gathers the checks and memories for the task.

Checks from the sitting include a shell warning. ljos warns about a shell command and does not stop it. ljos-policyd names a short list of dangerous actions. It is not a sandbox. A command that runs as you, outside a tool call, is not checked. If policyd is missing, slow, or crashes, the command runs and ljos logs a warning. Warning lines sit apart from ballots and votes, which are also separate from memory. A person stores a lesson with ljos remember, or a preference with ljos prefer. The words are kept as written. At the end of a session, ljos reads the transcript. It keeps up to five sentences that state a rule, a cause, or a fix. Each sentence is a note on the open sitting. The prompt hook does not show that note as a fact. Set LJOS_EXTRACT=off to skip the read. With no open sitting, it writes nothing.

A person can also record a grant that lets a seat close tickets. The grant stores the person's quote.

[//]: # ([[[cog import ljos_version as v; v.lines("These notes describe ljos {version}.")]]]) These notes describe ljos 0.39.0. [//]: # ([[[end]]])

Try it

Linux and macOS are supported. Windows works through Windows Subsystem for Linux (WSL) and is untested.

curl -fsSLO https://github.com/leidarljos/ljos/releases/latest/download/install.sh && sh install.shexport PATH="$HOME/.local/bin:$PATH"ljos doctorljos prefer "Push a tag with git push origin TAG; --follow-tags skips lightweight tags."echo "how do I push the v0.32.0 tag?" | ljos hook --prompt --textljos due

The installer puts the programs in ~/.local/bin. It sets up the tracker and the memory writer, then runs ljos onboard. ljos doctor names any part that does not answer. The preference is stored as written. The hook then prints that preference ahead of the prompt. ljos due lists what is ready to grade.

What a seat does

  • Two agents do not take the same ticket, because the seat files it and then claims it.
  • A seat votes on a decision, and reads how the votes settle.
  • A seat writes notes on the ticket, and reads what the other seats wrote.
  • A person stores a lesson on purpose. It is kept as written, and it comes back when it bears on a prompt.
  • A seat cites deeds, the records of what a piece of work produced.
  • A seat hands another seat a signed bundle. The receiver checks the bundle.

Some rules hold everywhere. Citing a deed does not merge anything. Finishing a claim does not close the ticket. A person closes it. Cards are notes a person froze. Agents read them and do not write them. Consensus is a separate program.

Install

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

The programs go to ~/.local/bin. The installer checks each download against its published SHA-256 sum. It also checks the build attestation when gh 2.49 or newer, or cosign, is there. Where a platform has no release build, cargo compiles the programs from source. The compile needs Rust 1.89 or newer.

The installer then runs ljos onboard for each coding runner it finds. With none found, it still sets up the tracker, the pack writer and the deed store.

The programs are ljos, ljos-mcp, packset, vissue, deedar, claimdag, ljos-policyd and ljos-consensus. packset-embed is the encoder for meaning-based search. --no-embed leaves it out, and search then matches words only.

ljos upgrade moves each installed program to its latest published release. ljos, ljos-mcp and ljos-hud come from the ljos release. Each other program comes from the repository that publishes it. One line a program names the version it had and the version it has, or current when those are the same. A missing release, a failed download or a checksum that does not match is a warning, and the other programs still move. ljos upgrade --only NAME moves one program. The previous binary is kept as NAME.bak-pre-VERSION.

To install by hand:

cargo binstall --locked ljos packset vissue-cli vissue-mcp deedar-cli claimdag-cli ljos-policyd ljos-consensusljos onboardljos doctor

ljos onboard writes the Model Context Protocol (MCP) entry, the hooks and the skill into each runner it finds. ljos onboard --dry-run shows what it would write. ljos onboard --example lists the runners ljos knows. ljos doctor says which part does not answer.

The part that does not answer can be the tracker path. Onboard makes no tracker inside a checkout of another project. A later git add -A commits a tracker left there. Onboard names the checkout. It asks for a VISSUE_ROOT outside the checkout. A path the checkout already ignores is fine.

Once the checkout path is fine, Codex runs a hook only after you trust it. Open /hooks in Codex and trust each ljos hook after ljos onboard, and again after an upgrade.

Take it off

ljos offboard --dry-runljos offboard

ljos offboard undoes what ljos onboard wrote. It removes the ljos entries from each runner's files. It leaves the rest of each file as it was. --runner NAME takes off one runner only. --dry-run lists what it would change. Onboard keeps its manifest and backups under ${XDG_STATE_HOME:-~/.local/state}/ljos/onboard.

ljos uninstall --dry-runljos uninstall

ljos uninstall takes ljos off the machine: it offboards every runner, puts the global git hooks back, stops the hook server and removes the ljos programs. Where ljos was, it leaves a stub that answers every hook call with an allow, because a runner that loaded its hook list while ljos was installed keeps calling that path until it restarts. --no-stub leaves nothing, --all removes the other seat programs too, --purge removes the state, data and configuration directories. A hand-deleted binary still has the same uninstall script from the release:

curl -fsSLO https://github.com/leidarljos/ljos/releases/latest/download/uninstall.sh && sh uninstall.sh

The seat's hooks fail open on every runner: a ljos that is missing, crashes or times out lets the call run, and a hook that fails answers allow with a note that says why nothing judged the call. scripts/fresh-install-check.sh installs into an empty HOME. A full session runs next. Offboard runs after that session. The last check confirms that HOME is clean.

Five minutes

ljos prefer "Push a tag with git push origin TAG; --follow-tags skips lightweight tags."echo "how do I push the v0.32.0 tag?" | ljos hook --prompt --text

Start a new session and ask for something the preference bears on. Before the model reads the prompt, the hook adds:

Remembered, oldest first (`ljos search` for more):- [preference, today] Push a tag with git push origin TAG; --follow-tags skips lightweight tags.

The hook uses a preference you type, and that preference takes effect at once. A lesson an agent writes at ljos finish is stored at once too, labelled agent-derived and unreviewed, and ljos accept ID marks it reviewed. A yes you said in chat is kept with the acceptance. The seat that heard it runs ljos accept ID --quote "..." --at TIME --via SEAT, and the acceptance keeps those words.

Two seats on one ticket

Two agents, alice and bob, each name their seat with LJOS_SEAT on the command. Alice adds both seats. One shell can then file, claim, vote, note and read. That shell casts one ballot. Bob writes a note from this shell. His ballot has to come from his own runner.

Seats cast ballots, and ljos consensus settles them. With two or more active seats, a protected push needs votes from two model families. A model family is the model a seat's verified record names. A seat with no such record is a family of its own. One active seat settles that check with its own vote. A panel seats each persona the ticket speaks to. Each persona casts its own ballot.

LJOS_SEAT=alice ljos seat add aliceLJOS_SEAT=alice ljos seat add bobid=$(LJOS_SEAT=alice ljos file "Pick a fuse" -p demo -t decision --options keep,drop | awk 'NR==1 { print $1 }')printf '%s\n' "$id"LJOS_SEAT=alice ljos claim "$id" --assignee aliceLJOS_SEAT=alice ljos vote "$id" --for keep --used noneLJOS_SEAT=bob ljos note "$id" "the patch is one file"LJOS_SEAT=bob ljos recall "$id"LJOS_SEAT=alice ljos consensus "$id"LJOS_SEAT=alice ljos digest

A second claim on a held ticket prints label claim-conflict: and names the holder. The ticket stays with that holder. A close with open children prints label children-open: and leaves the parent open. A block that would loop prints label graph-cycle: and does not store the edge. A persona ballot records the casting seat, the parent session and the persona. Every ballot is recorded. Ballots count as one voice when they share a session id, a parent, a calling shell or the root session of one agent runner. When they disagree, the latest ballot is that voice. ljos consensus names the ballots it folded and why, including that shell or agent runner. A subagent of that root session counts with its parent. A seat ballot is its own voice only when the cast has no shell, no agent runner and no earlier row.

The ballot list goes to ljos consensus. The command reads the pack's trust rows. The consensus crate settles the votes. With no rows, every voter weighs the same. ljos learn ID --outcome OPTION moves the rows toward the voters who turned out right.

Seats

The tracker's vissue.toml lists the seats.

ljos seat add carol

ljos seat add NAME writes the seat's row in vissue.toml, so nobody edits the file by hand. ljos seat prints the name this agent works under and where the name came from. That name is LJOS_SEAT when it is set. Otherwise ljos derives one from the runner, and a derived name counts as a seat.

Grants. A close=own grant lets one named seat close the tickets it filed or has claimed. An id list in close=ID[,ID...] names those tickets, and that seat may close no others. --ids-file PATH reads the ids, one per line. Without a grant, ljos finish leaves the ticket open for the person to close.

ljos seat grant SEAT close=own --quote "the person's words" --at ISO_TIME --via RECORDERljos seat grant SEAT close=ID[,ID...] --quote "the person's words" --at ISO_TIME --via RECORDERljos seat grant SEAT --ids-file PATH --quote "the person's words" --at ISO_TIME --via RECORDER

The vissue.toml row records the quote, the time, the recorder named by --via, and the tracker commit. Three rules apply:

  • A grant edited into vissue.toml by hand is ignored.
  • A seat cannot grant itself.
  • Every close cites the grant record.

Solo mode. 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.

What happened

ljos digest reads the tracker and says what the seats did: what each filed, claimed, voted on, noted and finished. You read the same facts one at a time with ljos timeline ISSUE, ljos claims and ljos log --seat NAME.

What policyd does

Before an agent's shell command runs, the runner's hook hands it to ljos hook. ljos hook asks ljos-policyd and relays the answer. policyd is the one place that says whether a command is dangerous. ljos does not run a second set of command checks of its own. By default nothing ljos answers stops a command: it never refuses or asks about one, and it never blocks one. A cloud seat's push rule, below, is the one exception.

policyd gives one of three answers.

AnswerWhat happens
allowThe command runs.
warnThe command runs, and the runner shows one line that names the rule and says why.
rewritepolicyd returns a corrected command, and that one runs.

block-on-warning does not block. A deny or prompt from policyd, including one printed because a named policyd_config sets block-on-warning true, is a warning with that label. The command runs. The hook does not deny the tool call, and a guard shim does not stop it.

Security: a warning is the only thing between a runner and a destructive command. Keep backups. Protect branches on the forge. Put the runner where it cannot reach what it must not touch.

policyd reads the command as a shell does. It looks through sh -c, env, timeout, xargs and nohup, through $cmd and pipes, and through quotes. It does not run a shell and does not read scripts. The first rule that fires is the warning.

policyd warns on these commands.

  • sudo, and curl or wget piped to a shell, including decoded text piped to a shell.
  • chmod that sets setuid, and raw disk writes such as dd of=/dev/sda and mkfs.
  • rm -rf outside the work tree and /tmp, and recursive chmod or chown on system trees.
  • a force push to main, master, develop or a protected branch, and deleting a remote branch.
  • git filter-branch, git filter-repo, git reflog expire, and deleting a published ref.
  • throwing away uncommitted work with git reset --hard, git clean -f, git checkout . or git stash clear.
  • reading a named credential file, or sending one over the network.
  • writes to the hook files, the policy files and the ljos programs.
  • outbound mail whose From is not your own address.

A recursive delete outside /tmp runs all the same, and so do a force push, deleting a remote branch and a write to the hook files, the policy files or the ljos programs. It prints the rule and its warning on one line, allow\twarn\tRULE\tWARNING, and keeps the label in $XDG_DATA_HOME/ljos/bypass.jsonl.

A lease push to a feature branch is allowed. An ordinary push of a branch is allowed.

The hook hands the runner this answer for git push --force on a topic branch. The push runs:

{"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":"allow\twarn\tgit-force-push\ta force push rewrites a published branch"}}

The rewrite

Some commands are not dangerous, only wrong for this project. policyd can answer with a fixed command. Its first rewrite runs the command through uv run. The answer is one line of text: allow, then rewrite, then the new command, separated by tabs.

The new command runs only when the guard has no warning on it. Claude Code, Codex, Grok Build and Cursor's preToolUse take it back from the hook and run it. A runner that has no field for this runs the old line, with a warning that names the new command. Each swap also shows a note naming both commands and leaves a row in $XDG_DATA_HOME/ljos/rewrite.jsonl. Set rewrite = false in a repository's ljos.toml to run its lines as written. The log keeps a row for a swap it declined too. policyd keeps a log of what it warns on.

The two checks ljos keeps

Only ljos knows the tracker and the sitting, so it keeps two checks.

  • A command or file tool that writes the tracker's files by hand gets a warning. Use ljos file, ljos note, ljos vote and ljos finish. Ticket text is data and is never read as a command.
  • A protected-branch push warns when the current sitting's ticket has no settled consensus. The push runs. With one active seat, that seat's own vote is the consensus for the push check. With two or more seats, the normal quorum applies. The pre-push git hook, once installed, still keeps that push under a runner.

If ljos-policyd is missing or slow, the command runs and ljos logs a warning. ljos doctor shows the policy row. ljos policy -- COMMAND prints the answer for one command without running it:

$ ljos policy -- rm -rf /usr/share/foorm -rf /usr/share/fooallow	warn	rm-rf-outside-tmp	a recursive delete reaches outside /tmp and /var/tmp

The command check is separate from the git hook. A git hook books the work. ljos git-hooks install adds a post-commit hook. On the first commit, it opens the sitting or names the one already open, and it notes the commit's SHA on the held ticket. It never refuses a commit.

Jev

Jev is an optional hosted model. It is off by default. The host named in ~/.config/ljos/jev.toml runs it. Without that file, ljos calls no model. What leaves the machine is the prompt and the candidate memories.

When ljos calls the model, the model does not judge shell commands. Jev answers questions the seat would otherwise answer with word lists and one subagent per voter. Jev answers which memories, which ballots, and which claims:

  • which memories bear on a prompt, and whether the prompt corrects the agent.
  • a persona's ballot on a decision, with its confidence and a forecast of the other votes.
  • whether an agent has claimed work done beside a failing test when the agent stops.
  • whether a memory that is due for review is still true.

A call sends the prompt and candidate memories off the machine. Every answer goes to a local log. A ballot Jev casts is recorded as judge:MODEL, not as a person or a persona, and counts as advice. When Jev does not answer, ljos uses the local answer.

Cloud VMs

ljos cloud up puts a fresh machine on the shared tracker. sh scripts/install.sh --cloud does the same from a checkout. A cloud seat has one push rule. It may push the branches named in its ljos.toml and develop. A cloud seat cannot force push, delete a remote branch or tag, or push to a branch outside its allowlist. A local git branch -d or git branch -D runs and prints allow\twarn\tgit-branch-delete. Every other push from a cloud seat runs with a warning. Opening or merging a pull request is not refused. ljos mesh up joins the swarm's tailnet on a Headscale login server, and ljos mesh down leaves it. docs/cloud-vm.md has the environment file, the push mode and the mesh.

Commands

ljos file "TITLE" -p PROJECT [-t decision --options A,B]ljos sitting ISSUE            # checks, memories for the task, and the claimljos claim ISSUE --assignee NAMEljos note ISSUE "..."ljos vote ISSUE --for OPTION --used noneljos consensus ISSUEljos finish ISSUE --lesson "..." [--outcome OPTION]ljos recall ISSUEljos timeline ISSUEljos claimsljos digestljos seat                     # who is sittingljos seat add NAMEljos seat grant SEAT close=own --quote "..." --at ISO_TIME --via RECORDERljos seat grant SEAT close=ID[,ID...] [--ids-file PATH] --quote "..." --at ISO_TIME --via RECORDERljos offboard [--runner NAME] [--dry-run]ljos remember "the default fuse is CombMNZ"ljos prefer "CombMNZ over RRF"ljos memory export --out memories.jsonlljos memory import memories.jsonlljos memory integrate --allljos memory importsljos search fuseljos island "rebuild the site"ljos dueljos graded ID [--lapsed]ljos forget ID --why DEEDljos accept ID [--quote "..." --at ISO_TIME --via SEAT]ljos trust alice bob 0.8 --why DEEDljos learn ISSUE --outcome OPTIONljos handover --out DIR --issue ISSUEljos receive DIR [--import]ljos send SEAT "text"ljos inboxljos policy -- COMMANDljos onboardljos doctorljos protocol

remember and prefer write one claim to the pack, stored as written. They do not read a transcript. forget retires a claim and keeps the record that it was held.

The MCP server

ljos-mcp serves the same verbs over stdio. By default it lists twenty core tools, guard and memory first: rule, prefer, remember, search, start, guard_check, file, options, note, recall, sitting, finish, claim, release, send, inbox, reply, vote, consensus and doctor, each with the prefix ljos_. Every listed tool costs its description and schema on every session. measurements/mcp-size.txt records 7,865 tokens for the core set against 17,781 for all fifty-two. LJOS_MCP_TOOLS=all lists every tool. Cards are the resources ljos://cards/USER.md and ljos://cards/MEMORY.md, and the protocol is ljos://protocol.

json
{"mcpServers": {"ljos": {"command": "ljos-mcp"}}}

The official Model Context Protocol (MCP) Registry lists the server from the crates.io page of ljos, and checks this line there:

  • mcp-name: io.github.leidarljos/ljos

server.json stores the registry entry, and a release tag publishes it.

Check an install

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

The script installs into an empty HOME and onboards. It takes two seats through file, claim, vote, consensus, note, recall and digest. Then it runs ljos offboard and checks that HOME is clean. It prints each step that failed.

Documentation

The site is https://leidarljos.github.io. The crate docs are at https://leidarljos.github.io/ljos/.

PageAnswer
Getting startedInstall, two seats on one ticket, offboard
How-toHooks, onboarding, handover, trust
ReferenceEvery verb, tool and variable
ExplanationThe reason for the design

来源:README.md,提交 468f837

工具

0
SourceWeft 尚未在沙箱中启动过该软件包,因此其工具未知。

版本历史

16
  1. v0.39.0最新Nov 7, 2026
  2. v0.38.1Nov 5, 2026
  3. v0.38.0Nov 3, 2026
  4. v0.37.0Nov 3, 2026
  5. v0.35.10Nov 1, 2026
  6. v0.35.8Oct 31, 2026
  7. v0.35.6Oct 31, 2026
  8. v0.35.3Oct 31, 2026
  9. v0.35.2Oct 30, 2026
  10. v0.35.0Oct 29, 2026
  11. v0.33.0Oct 22, 2026
  12. v0.32.1Oct 21, 2026
  13. v0.32.0Oct 20, 2026
  14. v0.31.0Oct 19, 2026
  15. v0.30.0Oct 17, 2026
  16. v0.29.0Oct 14, 2026

评分

已满足适用检查项的 50%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分

    请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。

  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具15 分

    请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。

  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分