Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Before calling any change done, `cargo fmt --all`, the `clippy` line above, and

## Workspace

36 crates organized into six layers, with `goat-protocol` at the bottom of the dependency DAG:
37 crates organized into six layers, with `goat-protocol` at the bottom of the dependency DAG:

**Infrastructure**
- `goat-protocol` — shared wire contract (`Op`, `Event`, `TaskId`); serde only; leaf.
Expand All @@ -29,6 +29,7 @@ Before calling any change done, `cargo fmt --all`, the `clippy` line above, and
- `goat-wire` — daemon/client wire contract; leaf (depends on `goat-protocol` only). The `ClientFrame`/`ServerFrame` envelope ({`SessionId`/`ClientId`/`seq` + payload `Op`/`Event`}), length-delimited JSON codec (`WireConn`), and protocol-version handshake. `Op`/`Event` bodies are wrapped, never modified.
- `goat-daemon` — the resident `goatd` (`goat daemon serve`); machine-wide single daemon holding N live sessions keyed by cwd. Owns the session registry, a single seq-stamping event-log pump per session (stamp→log→fan-out), per-window bounded delivery with disconnect-on-overflow, presence broadcast, idle eviction (kept alive while a turn runs or a window is attached or an Ask/Plan is open), orphaned-turn sweep on startup, and the unix-socket listener (`~/.goat-code/daemon.sock`, 0600). Allocates per-session `TaskId`s and echoes a correlation token.
- `goat-client` — thin transport the TUI talks to; auto-spawns the daemon if absent, performs the handshake, opens/reattaches a session, and exposes the same `Op`/`Event` channels the TUI already consumes. Owns the bidirectional `IdMap` (client-local ↔ daemon `TaskId`) and seq-gap resync.
- `goat-remote` — network-facing remote access for the daemon. mTLS over WebSocket: the daemon is a tiny `rcgen` CA, devices pair once over an HTTP `/pair` endpoint (one-time high-entropy code, server cert pinned by QR fingerprint, CSR signed by the CA) and thereafter connect to `/ws` presenting their device client cert. A custom `ClientCertVerifier` validates the chain and checks the cert fingerprint against the live device registry on every handshake (revocation works here, no CRL/OCSP). The TCP listener self-gates: it binds only while at least one device is paired or a pairing code is pending, and winds down otherwise — there is no separate enable flag. Depends on `goat-wire`/`goat-protocol` only; `goat-daemon` supplies a `RemoteHandler` that bridges each authenticated WS connection into the shared connection driver as `ClientOrigin::Remote`. Remote = local trust; only pairing issuance and `StopDaemon` stay local-only.
- `goat-update` — executable replacement helper for `goat update`; small CLI-only crate with no app-state ownership.
- `goat-worktree` — git-worktree management (`enter`/`list`/`remove`); `enter` resolves and returns the worktree path (the agent cwd is injected explicitly, not via process `set_current_dir` for the engine).

Expand Down
190 changes: 190 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ goat-worktree = { path = "crates/goat-worktree" }
goat-wire = { path = "crates/goat-wire" }
goat-daemon = { path = "crates/goat-daemon" }
goat-client = { path = "crates/goat-client" }
goat-remote = { path = "crates/goat-remote" }

tokio = { version = "1", features = ["rt-multi-thread", "macros", "sync", "time", "signal", "net", "io-util"] }
tokio-util = { version = "0.7", features = ["rt", "codec"] }
Expand Down Expand Up @@ -96,6 +97,13 @@ tracing-appender = "0.2"
color-eyre = "0.6"
thiserror = "2"

tokio-rustls = { version = "0.26", default-features = false, features = ["ring"] }
rustls = { version = "0.23", default-features = false, features = ["ring", "std"] }
rustls-pemfile = "2"
rcgen = { version = "0.14", default-features = false, features = ["ring", "pem", "x509-parser"] }
tokio-tungstenite = "0.28"
qrcode = { version = "0.14", default-features = false }


[workspace.lints.rust]
unsafe_code = "forbid"
Expand Down
Loading
Loading