Codync
免费开源的 1:1 Grok Bot 与 Muse 替代方案。可在 iPhone、Mac 或 Linux 桌面上将 Claude 代码、Codex、Cursor 以及 40 多个编码代理作为持久机器人使用。支持群组聊天、线程、应用。
AI 翻译
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Agent accessibility layer for TUIs. Ratatui apps publish their widget tree, focus and available actions so AI agents act on nodes instead of scraping screens.
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗ARIA for terminals. ARIA is the set of attributes a web page uses to tell screen readers what each element is and does. taria brings that idea to terminal user interfaces (TUIs), with AI agents as the readers. A TUI app declares its live widget tree, focus state, and available actions through a small protocol. A bridge serves that tree to any agent harness, the program that runs a model and hands it tools (Claude Code, OpenCode, Cursor), over MCP, the Model Context Protocol that harnesses use to call tools. The harness drives the app through ordinary MCP tools, with no taria-specific code of its own.
The client on the right is a script, demo/drive.py, not a model: it makes
six fixed tool calls through the real taria-mcp bridge.
Try it: cargo run -p taria-demo in a clone of this repository, then the
Quick start. In your app: one dependency, a publish after
each draw, and a drain in your event loop.
Agents today reach TUIs by scraping rendered screens through tmux or headless terminals and guessing at structure. taria works on the other side of the terminal: the app publishes what is on screen semantically, the way a GUI app hands its accessibility tree to screen readers and test tools.
Status: alpha, at 0.4.0. The wire format is frozen at
PROTOCOL_VERSION1, so an app and a bridge built months apart still work together. The Rust API may still change in a 0.x minor release, and each such change gets an upgrade note in CHANGELOG.md. CI tests Linux, macOS and Windows.
In a benchmark on 2026-10-12, at commit 3e66fbb, shortly before 0.3.0, Claude Haiku 5.5 passed 30 of 30 runs reading taria's JSON tree, with a median of 14,045 tokens read and 3 tool calls per run, and 29 of 30 reading the screen through tmux, with 26,722 tokens and 6.5 tool calls. On Sonnet 5.5 the two were close: tmux used 7.7% fewer tokens than taria's JSON tree, and 1.7% more than its outline format. Method and caveats: bench/RESULTS.md.
A ratatui app publishes nodes after it draws and takes agent input in its event loop, beside its terminal events:
use taria_ratatui::taria::{Action, Node, Role};
use taria_ratatui::{InputStatus, TariaLayer};
// Never fails: if taria cannot bind, the layer does nothing.
let mut layer = TariaLayer::bind_or_disabled("my-app");
loop {
terminal.draw(|frame| view(&app, frame))?;
// Say what is on screen, after every draw.
layer.publish([Node::new("save", Role::Button)
.label("Save")
.action(Action::Activate)]);
wait_for_event(&mut app)?; // your event handling, unchanged
layer.drain(|input| {
app.apply(input); // as if a person had done it
InputStatus::Delivered // or Ignored, if it did nothing
});
}
docs/integration-guide.md walks through adding taria to an app you already have, including the loop's timing rules.
Two sides, two different things to install.
Writing a TUI app that agents should be able to use. One dependency:
cargo add taria-ratatui
It re-exports the protocol crate, so taria::{Action, IdSpace, Node, Role}
is reachable as taria_ratatui::taria::{...} without a second dependency.
Driving an app that already speaks taria. Install the bridge binary:
cargo install taria-mcp
Or take a prebuilt build from the
releases page: a tag builds
taria-mcp as a tarball for x86_64 and aarch64 Linux and for both macOS
architectures, and as a .zip for x86_64 Windows
(taria-mcp-x86_64-pc-windows-msvc.zip, holding taria-mcp.exe), each with
its sha256. On macOS, if Gatekeeper (the check macOS runs on downloaded
programs) blocks the binary, clear its quarantine flag with
xattr -d com.apple.quarantine taria-mcp. Then point your harness at it,
with the app's label:
claude mcp add taria -- taria-mcp --app <label>
On Windows both sides work the same way, from the same commands: the app and
the bridge meet over a named pipe (Windows' local IPC channel) instead of a
Unix socket, and neither needs a cfg or a flag of its own. Put
taria-mcp.exe somewhere on your PATH, or give the harness its full path.
The quick start below uses the demo app in this repository instead, which needs nothing installed.
Prerequisites: a Rust toolchain (1.88 or newer) and, for step 2, the
claude CLI. Three steps, two terminals. The commands are written for Linux
and macOS. On Windows, steps 1 and 3 are the same, and step 2 says what
changes.
Run the demo app in one terminal. It prints its taria socket path on startup and then behaves like a normal task-manager TUI:
cargo run -p taria-demo
Register the bridge with your agent harness. Build it first, then for Claude Code:
cargo build -p taria-mcp
claude mcp add taria -- $(pwd)/target/debug/taria-mcp --app taria-demo
On Windows, run the same build, then give claude mcp add the full path
of target\debug\taria-mcp.exe in place of
$(pwd)/target/debug/taria-mcp.
Working inside this repo, you can skip claude mcp add: the committed
.mcp.json registers the same server, and Claude Code picks it up here
once you approve it.
Ask the agent to drive the app: "read the tree, add a task called ship
v0, mark it done, then delete it". The agent works through the
read_tree, act, type_text, and key tools while the TUI reacts in
the first terminal.
On Linux and macOS, backgrounding the demo with plain & fails. Give it a
terminal with tmux instead:
cargo build -p taria-demo
tmux new-session -d -s taria-demo -x 120 -y 34 './target/debug/taria-demo'
tmux capture-pane -p -t taria-demo # peek at the screen without attaching
tmux kill-session -t taria-demo # stop it when you are done
Windows has no tmux. There, run the demo in one terminal and start the harness in another.
The app publishes a semantic snapshot of its widget tree over a Unix domain socket, or a named pipe on Windows, one JSON object per line (ndjson), on every meaningful change. The bridge holds the latest snapshot and exposes it, plus input back into the app, as MCP tools. Agent input reaches the app's event loop like any other input source, and the app acknowledges each input by id, so the bridge can tell an input the app acted on from one it never saw. The bridge connects on its first tool call and lets the app go after 60 s with no tool calls by default, so an idle agent session does not keep the app from another.
+---------------+ Unix socket +-----------+ MCP over stdio +---------------+
| TUI app | <------------> | taria-mcp | <--------------> | agent harness |
| taria-ratatui | or Windows | bridge | | (Claude Code) |
| | named pipe | | | |
| | (ndjson) | | | |
+---------------+ +-----------+ +---------------+
What an app can say about a widget is a fixed vocabulary: 29 roles (list,
tree, table, text_input, select, dialog, log, chart,
scrollbar, terminal and the rest) and 7 actions (activate, focus,
select, toggle, scroll, set_value, dismiss), plus a custom action
for anything an app names itself. Both vocabularies are open: a peer that
meets a role or an action it does not know degrades that one field instead of
failing the tree, which is what lets either grow inside a frozen format. A
node can also carry typed state: whether it is selected, checked, expanded
or disabled, a number and its bounds, and where it sits in a list or a
table.
| Tool | What it does |
|---|---|
read_tree | Returns the app's current semantic tree as JSON: node ids, roles, labels, values, focus, typed state such as selected, checked or disabled, the actions each node advertises, and a relayed mark on any node whose text came from outside the app, which the agent reads as data. The app's own snapshot minus its type key and its input stamp, every other field kept, so a role or field this bridge has never heard of arrives under its real name. With --tree-format outline, the same snapshot comes as one indented line per node instead, which for the demo's first tree is about half the characters. |
act | Invokes an advertised action on a node by id, with an optional value (e.g. for set_value), up to 4096 characters. The node id and the action are checked against the latest tree before anything is sent, and an act on a node marked disabled is refused. |
key | Sends a raw key press ("q", "enter", "ctrl+c"), up to 64 times with repeat. A key that does not match the grammar is rejected here rather than swallowed by the app. A fallback for parts of the UI without semantic coverage. |
type_text | Types a literal string in one call instead of one key call per character, up to 4096 characters. It goes where the app puts typing, never through the app's key bindings, so move the keyboard to the target first: act on its advertised focus action, or on set_value, which many apps focus as a side effect. An app accepting no typing reports it ignored rather than acting on the characters. |
The three input tools wait for the app's answer and report what actually
happened: the updated tree, an input the app deliberately ignored (with the
current tree to re-plan from), an input the app acknowledged and did not
survive (an advertised quit, working), or an error for an input that was
dropped, never applied, or left unaccounted for by an app that went away
before acknowledging it. A taria-ratatui 0.4.0 app stamps each tree with the
newest input it took, so the answer is the tree published after that input:
up to 3 s for a slow handler, and "did not change" within a frame for an
input that changed nothing. Against an app that does not stamp, the wait is
500 ms, as before.
The bridge takes exactly one of --socket <path> or --app <label>. With
--app, it resolves the socket path the same way the app-side adapter does
when binding. --tree-format outline serves the tree as an indented outline
instead of JSON. --idle-release <SECS> sets how long the bridge waits with
no tool calls before it lets the app go: 60 by default, 0 for never. The
flags, the environment variables, the resolution order, the rule on labels
and the outline's grammar:
docs/cli.md.
crates/taria Core protocol types (widget tree, actions, snapshots)
crates/taria-ratatui Ratatui adapter: publish semantics alongside rendering
crates/taria-mcp MCP bridge binary for agent harnesses
examples/demo-app Demo ratatui app driven by an agent through taria
scripts/ Python verification harnesses (e2e, adversarial)
docs/ Protocol spec, architecture, integration guide,
comparison, landscape research
bench/ Benchmark harness and results: taria against tmux
demo/ The GIF above and the scripted client that records it
In docs/:
protocol.md
specifies the wire format message by message,
architecture.md
explains why it is shaped that way, and
landscape.md
is the research behind both.
cargo check --workspace
cargo test --workspace
cargo clippy --all-targets -- -D warnings
cargo fmt --check
python3 scripts/e2e.py # end-to-end: 27 steps, demo app + bridge + MCP
python3 scripts/adversarial.py # 24 edge-case probes
CONTRIBUTING.md covers the rest: the setup, the CI gate, the commit style, and what a change has to clear while version 1 of the wire format is frozen.
See docs/compatibility.md for the full list. The three that decide whether taria fits at all:
PROTOCOL_VERSION 1: changes within
version 1 are additive, so a version difference costs a degraded field
rather than the whole tree.
What the freeze promises.Dual-licensed under MIT or Apache-2.0, at your option.
The MCP registry reads the line
below to check that the taria-mcp crate belongs to this server.
mcp-name: io.github.y0sif/taria-mcp