herdr-gpui
AGENTS.md1.7k starsChanged 8 days agoApache-2.0View on GitHub
Engineering guidance for agents working in this repository. Read this alongside README.md, the relevant crate documentation, and the code before making changes. - Keep changes small, explicit, and focused on the root cause. - Preserve user and other agents' changes. Never revert unrelated edits. - Prefer existing standard traits and generics over unnecessarily concrete APIs. - Protect protocol compatibility, bounded resource use, and UI responsiveness. - Add regression tests for changed behavior and report what was actually verified. - Never…
- Commits and pushes
We split this AGENTS.md into the rules it gives an agent
58 rules. About 2 are common, 26 are distinctive, and 30 are very specific to this project.
≈2
Common · estimate
Many files like this have a rule of this kind.
≈26
Distinctive · estimate
This author's own choices. Worth a look.
30
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Distinctive: line 8
Keep changes small, explicit, and focused on the root cause.
- Distinctive: line 10
Prefer existing standard traits and generics over unnecessarily concrete APIs.
- Distinctive: line 12
Add regression tests for changed behavior and report what was actually verified.
- Distinctive: line 13
Never modify or patch Herdr itself.
- Distinctive: line 48
Keep dependency direction from UI to client to protocol.
- Distinctive: line 49
Keep session transitions separate from socket scheduling, and connection ownership separate from window rendering.
- Very specific: line 51
File size limit: 1,000 lines: No Rust, Python, shell, or Swift file may exceed it, tests included.
- Very specific: line 56
Keep APIs narrow. Use private items by default and pub(super) or pub(crate) only where needed.
- Distinctive: line 58
Do not add a crate, runtime, service container, or speculative transport abstraction without a concrete need.
- Very specific: line 66
Do not assert hard-coded totals such as assert_eq!(list.len(), 55) or fixed array lengths like [T.
- Very specific: line 72
Keep lists whose order carries no meaning (enum variants without derived ordering, asset tables, registries) sorted between // keep-sorted …
- Distinctive: line 85
Do not mirror its variants in the app's root and convert one by one: each failure has one definition, and callers match the nested variant.
- Very specific: line 114
When a feature adds something an agent or script could reasonably ask for (open or focus a view, read state the app holds, change a …
- Very specific: line 120
Do not add a command that repeats Herdr's own herdr CLI (workspaces, terminal tabs, panes, agents, scrollback), that the app cannot really …
- Very specific: line 128
Keep the shared contract: --json and --window on every command, the exit-code table in docs/cli.md, bounded requests and responses, and …
- Very specific: line 131
Add the command to docs/cli.md.
- Very specific: line 140
Use slices, &str, and &Path when borrowing is sufficient.
- Very specific: line 141
Prefer impl Trait or named generics for static dispatch.
- Very specific: line 142
Use FnOnce, FnMut, or Fn for injectable behavior.
- Distinctive: line 143
Do not introduce custom traits merely to wrap one struct.
- Distinctive: line 144
Use enums for closed alternatives such as navigation targets, pane/popup input destinations, connection phases, and launch modes.
- Distinctive: line 146
Prefer typed request/result structures when shapes are known.
- Very specific: line 148
Every crate must expose its own root Error and Result<T, E = Error> (pub use error::{Error, Result}), with errors defined using thiserror.
- Very specific: line 149
Use anyhow::Result and context at application/reporting and test-harness boundaries, not as a replacement for typed internal errors.
- Very specific: line 150
Never use String or &str as an error type, including Result<(), String>, worker-channel results, and intermediate operation state.
- Distinctive: line 152
Test error variants and source chains as well as user-facing diagnostics.
- Very specific: line 154
Prefer safe Rust. Do not introduce unsafe unless there is no practical safe alternative.
- Distinctive: line 155
Prefer guard clauses and readable iterators.
- Very specific: line 160
Treat app, window, and entity contexts as UI-thread execution.
- Distinctive: line 161
Never perform blocking socket/disk I/O, process waits, sleeps, or expensive background computation on the UI thread.
- Very specific: line 162
Start child processes with herdr_client::new_command, never Command::new (clippy rejects it outside tests).
- Distinctive: line 163
Keep render and input paths thin.
- Distinctive: line 168
Use the same geometry for painting, hit testing, and IME placement.
- Distinctive: line 169
Keep glyph visibility separate from decorations: spaces and wide-character continuation cells may still need underline/strikethrough …
- Very specific: line 178
Keep frame/response/geometry bounds, strict decoding, and atomic patch validation.
- Distinctive: line 179
Never mix snapshot metadata and surface cells across boot IDs or projection revisions.
- Common: line 186
Never commit secrets, credentials, private terminal output, or machine-local configuration.
- Very specific: line 190
Put dependency versions in root [workspace.dependencies].
- Very specific: line 191
Use the pinned rust-toolchain.toml and GPUI version.
- Distinctive: line 192
Keep workspace lint inheritance and fix warnings rather than widening allowances.
- Very specific: line 193
Keep integration-test opt-in.
- Distinctive: line 194
Do not introduce Tokio or another runtime to wrap the existing blocking socket worker.
- Very specific: line 195
Avoid unrelated lockfile upgrades.
- Distinctive: line 205
Commit subjects are the changelog entries, verbatim apart from a capitalized first letter.
- Very specific: line 227
Prefer the existing just recipes.
- Distinctive: line 253
Add deterministic tests for invariants: ordering, cancellation, fragmentation, revision fencing, error paths, geometry, and cleanup.
- Very specific: line 254
Test pure session/CLI/geometry logic without a socket or window where possible.
- Very specific: line 255
Keep test bodies out of production files, which only declare #[cfg(test)] mod tests;.
- Very specific: line 256
Put tests for a new feature in a new topic file under the module's tests/ directory (for example keymap/tests/pane_keys.rs, starting with …
- Distinctive: line 263
Keep CLI parsing pure and based on OS strings so socket paths need not be UTF-8.
- Distinctive: line 282
Only commit, push, or create/update a PR when requested.
- Common: line 283
Before committing, inspect status, diff, and recent history.
- Very specific: line 284
Use conventional commit subjects (feat, fix, refactor, test, docs, chore).
- Very specific: line 285
Never add AI attribution, assistant-session links, or tool vanity lines to commit messages or PR descriptions.
- Distinctive: line 291
Before creating a PR, review every included commit and the full diff from its base.
- Very specific: line 292
Run just ci on the exact commit before creating a PR or pushing to one, so failures surface locally instead of minutes later in CI.
- Very specific: line 296
After a green run, create or update a single PR comment saying just ci ran locally and passed: the commit SHA, the platform (for example …
- Distinctive: line 311
Keep user-facing docs and public API examples synchronized with behavior changes.
≈ “Common” is an estimate: at least 1 in 5 of the 36,368 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
AGENTS.md
Engineering guidance for agents working in this repository. Read this alongside
README.md, the relevant crate documentation, and the code before making changes.
Priorities
- Keep changes small, explicit, and focused on the root cause.
- Preserve user and other agents' changes. Never revert unrelated edits.
- Prefer existing standard traits and generics over unnecessarily concrete APIs.
- Protect protocol compatibility, bounded resource use, and UI responsiveness.
- Add regression tests for changed behavior and report what was actually verified.
- Never modify or patch Herdr itself. It is owned by an unrelated external team; sibling Herdr checkouts are read-only references. Propose an upstream PR only when genuinely justified, never make incidental upstream edits for this client.
Architecture
Herdr UI is a native client of an existing local Herdr daemon, not a terminal emulator, server, or TUI wrapper. Herdr owns terminal processes and session state. Closing or detaching the GUI must leave the daemon and its terminals running.
| Location | Responsibility |
crates/herdr-protocol | Generation-1 wire types, framing, validation, and atomic surface patches |
crates/herdr-acp | herdr-acp binary run inside a Herdr pane: the only ACP client of an agent, its in-pane chat view, the attach socket Herdr UI connects to, and Herdr status reports |
crates/herdr-chat-protocol | Attach wire between herdr-acp and its clients: transcript model, the shared change reducer, framing, and endpoint discovery; no ACP or GPUI types |
crates/herdr-client | Discovery, socket worker, session transitions, ordered commands, and client-local activity projection |
crates/herdr-gpui | Native UI, connection bridge, presentation state, semantic input, geometry, and painting |
crates/herdr-control-protocol | The control socket between herdr-gpui <command> and the running app: request and response types, bounds, and the Unix socket or named pipe; no GPUI |
crates/herdr-commands | The command catalog: each command's name, default shortcuts per platform, and the daemon request it becomes against a snapshot; no GPUI (the app binds the keys and runs window commands) |
crates/herdr-usage | Plan usage of AI services on a host: the providers, their probes and sign-ins, the registry, and the read worker; no GPUI (the app draws the status bar and panel) |
crates/herdr-credentials | Where saved sign-ins live: the store policy, the macOS Keychain, Linux Secret Service, Windows Credential Manager, and the private 0600 file; GitHub and the cloud providers keep their secrets here; no GPUI |
crates/herdr-github | GitHub sign-in (device flow, pasted tokens, the GitHub CLI, additional accounts), its REST and GraphQL transport, the [github] config table, the read-only pull request prefetch, and explicit pull request actions; no GPUI (the app keeps the account avatars, the shared PR store, and badge colors) |
crates/herdr-vcs | Git on the checkouts the app shows: working-tree status, commit, push, and pull request creation, checkpoints kept as Git refs on each host, and the code search index; no GPUI (the app runs the workers from its views) |
crates/herdr-orchestrator | The orchestrator's backend: issue and pull request records, the per-repository SQLite database, the GitHub, GitLab, and Beads readers, agent dispatch, and the worker; also the app's cache database and private-file setup; no GPUI (the app draws the sections and pages) |
crates/herdr-remote | Machines beyond this computer's daemon: the cloud providers (one feature each), their config tables and saved devices, running scripts on any host, and Teleport's core; no GPUI (the app runs its jobs and draws its views) |
crates/herdr-remote-control | Remote control from a phone. With the server feature, the herdr-remote-control daemon: HTTPS with its own CA, dual-approval pairing, Web Push, and chats and terminal tabs through Herdr's API socket. Without it, what Herdr UI uses: the daemon's control protocol, the [remote] config table, the user service install, and the pairing state; no GPUI, and no Tokio without server |
crates/herdr-updater | The in-app update service: release checks, signed manifests, staging, the install helpers, and the release identity (APP_ID, APP_VERSION); no GPUI |
crates/herdr-diagnostics | The app's log file and crash reports: the bounded capture of the crates the app names, the writer thread and rotation, the reader the log window tails, the panic hook, and Windows minidumps; no GPUI |
crates/herdr-gpui-launcher | Windows-only windowed launcher that starts herdr-gpui.exe without a console window; std plus MessageBoxW for start failures |
crates/herdr-automation | Automation scripts (docs/automations.md): the sandboxed Luau state, the step catalog, schedules, caps, and the plan a person approves; no GPUI or runtime |
crates/herdr-automate | The automation daemon and its command line: schedules approved scripts per host, runs their steps through the herdr CLI, keeps state in SQLite, and answers --json reports for Herdr UI |
crates/embed-resource | No-op stand-in for GPUI's embed-resource build dependency, patched in so GPUI embeds no Windows manifest beside crates/herdr-gpui/windows.manifest; not a production crate |
crates/test-support/sandbox.rs | Shared isolated process setup for opt-in integration tests; not a production crate |
crates/test-support/pe.rs | Windows executable (PE) reader for tests that check subsystem and resources; not a production crate |
- Keep dependency direction from UI to client to protocol. Protocol/client code must not depend on GPUI.
- Keep session transitions separate from socket scheduling, and connection ownership separate from window rendering.
- Reuse
ConnectionBridge, domain targets, geometry helpers, and the test sandbox rather than duplicating their policies. - File size limit: 1,000 lines. No Rust, Python, shell, or Swift file may exceed it,
tests included;
just check-file-sizeenforces it injust ciand CI's checks job. There is no allowlist: when a change would cross the limit, split the file by responsibility in the same change rather than adding an exception. - Split modules by responsibility; the line limit is a ceiling, not a reason for arbitrary cuts. Prefer wiring and exports in entry points as code grows; do not perform unrelated file reshuffles.
- Keep APIs narrow. Use private items by default and
pub(super)orpub(crate)only where needed; do not expose every field merely to ease extraction. - Define shared types once in the lowest appropriate layer and re-export them. Do not create mirror enums or convert between them through strings.
- Do not add a crate, runtime, service container, or speculative transport abstraction without a concrete need. Sibling checkouts are references, not build dependencies.
Parallel Pull Requests
Many pull requests are open at once, so code that every feature appends to is a merge-conflict hotspot. Most past conflicts were two branches adding lines at the same spot, or both bumping one hard-coded count.
- Do not assert hard-coded totals such as
assert_eq!(list.len(), 55)or fixed array lengths like[T; 98]for lists features grow. Compare against the source list, assert uniqueness or membership, or use a slice. - Declare each item of a growing list once. Prefer one table, or a
macro_rules!table, that generates the matchingmatcharms andALLlists over parallel lists edited in several places. - Keep lists whose order carries no meaning (enum variants without derived
ordering, asset tables, registries) sorted between
// keep-sorted startand// keep-sorted endmarkers. Additions then land on different lines.just check-sorted(part ofjust ci) enforces the markers andjust sortfixes them. Never mark a list whose order is shown to users or is a wire contract, such as menu rows or the vendored bincode types. - Give a new feature's failures their own
thiserrorenum namedErrorin its module'serror.rs, with variants not prefixed by the feature name, and add one#[error(transparent)] Feature(#[from] feature::Error)variant to the crate's rootError, aspane_moveandbackdropdo, rather than a run of variants inerror.rs. The root enum stays sorted. Callers name itfeature::Error, never through anas FeatureErroralias. - Wrap another crate's error the same way (
GitHub(#[from] herdr_github::Error)). Do not mirror its variants in the app's root and convert one by one: each failure has one definition, and callers match the nested variant. - Shared state structs (
HerdrWindow,Config,herdr_settings::Settings) and their constructors keep their fields sorted. Run an initializer that has an effect or depends on another (registering a subscription, creating an entity, reading a value before it moves) in aletbefore the struct literal, so the literal itself has no order to preserve. DeriveDebugrather than listing fields by hand; redact a private field through its own type'sDebug. just hooksalso enablesrerere, so a resolution is reused when the same conflict returns on another branch, and aCargo.lockmerge driver that keeps one side and has Cargo rebuild it before the commit. After a clean merge whose only conflict was the lockfile, the merge stops with the rebuilt lockfile staged: rungit commit --no-editto finish it. The rebuild refuses while aCargo.tomlorCargo.lockchange is unstaged, and an aborted merge's pending rebuild is dropped with a warning. Squash merges rebuild like merges. Cherry-picks, reverts, and rebases commit without these hooks, so they stop withCargo.lockconflicted: runcargo metadata,git add Cargo.lock, and continue. GitHub's Update branch button runs no hooks; there, runcargo metadataand commitCargo.lockby hand.
Command Line
herdr-gpui COMMAND drives the running app over its control socket, so
agents in Herdr panes can use what only this client shows or keeps
(docs/cli.md). Agents learn about it from the managed skill in
skills/herdr-gpui-browser/SKILL.md, which the app installs and refreshes.
- When a feature adds something an agent or script could reasonably ask for
(open or focus a view, read state the app holds, change a setting, wait for
an event), add a command in the same change: the request in
herdr-control-protocol'sprotocol, its handler incontrol/server, parsing and output incontrol/client, its--helptext, and tests for each. - Do not add a command that repeats Herdr's own
herdrCLI (workspaces, terminal tabs, panes, agents, scrollback), that the app cannot really do, or that skips a confirmation. Destructive or outward actions open the app's own dialog, pointed at the caller's checkout or the machines named, and the user confirms there; a batch of them is confirmed once. The one exception iscloud exec, a command on a cloud machine the user saved, which is the agent's own work and asks nothing, as the agent's shell does not. - Keep the shared contract:
--jsonand--windowon every command, the exit-code table indocs/cli.md, bounded requests and responses, and targeting that refuses rather than acting in another session's window. - Add the command to
docs/cli.md. When an agent should reach for it unprompted, also add it to the skill's command table and, if it is a new kind of task, to the skill'sdescription, which is all an agent sees before loading it. Keep the skill'sname: installed copies are found by it.
Rust Conventions
- Require only the capabilities an operation uses. Prefer existing traits such as
Read,Write,IntoIterator,AsRef<Path>, andAsRef<OsStr>over specific streams, collections, or owned paths. - Use slices,
&str, and&Pathwhen borrowing is sufficient. Keep owned data where it must cross a thread boundary or outlive its caller. - Prefer
impl Traitor named generics for static dispatch. Usedyn Traitfor actual runtime heterogeneity/type erasure, not by default. - Use
FnOnce,FnMut, orFnfor injectable behavior. Do not invent a callback or clock trait when a closure or explicit time value suffices. - Do not introduce custom traits merely to wrap one struct. A new trait needs a concrete behavioral contract and a real implementation/substitution need that existing traits cannot express.
- Use enums for closed alternatives such as navigation targets, pane/popup input destinations, connection phases, and launch modes. Avoid string dispatch and boolean-plus-ID pairs internally.
- Parse strings at boundaries, then match on domain types. Prefer
From,TryFrom,Into, andTryIntofor conversions. - Prefer typed request/result structures when shapes are known. Preserve genuinely open-ended protocol envelopes rather than forcing a speculative schema.
- Derive standard traits such as
Default,PartialEq, andEqwhere their semantics are valid. Compare complete values when deduplicating operations. - Every crate must expose its own root
ErrorandResult<T, E = Error>(pub use error::{Error, Result}), with errors defined usingthiserror. Use meaningful typed variants for internal failures and match on variants, never error text. - Use
anyhow::Resultand context at application/reporting and test-harness boundaries, not as a replacement for typed internal errors. Keep dependency versions in workspace dependencies. - Never use
Stringor&stras an error type, includingResult<(), String>, worker-channel results, and intermediate operation state. Strings are allowed as diagnostic payloads, unchanged wire-protocol fields, and final UI display text, not as catch-all internal error wrappers. - Propagate errors with
?; preserve original causes with#[from]/#[source]and retain structured operation/path context until the display boundary. Do not flatten sources withto_string()orformat!()during propagation. Keepio::Resultwhere an actual I/O trait or connector contract requires it, preserving typed sources when adapting errors. - Test error variants and source chains as well as user-facing diagnostics. Preserve redaction, bounded remote diagnostics, retry/cancellation classification, and protocol compatibility when changing error handling.
- No
unwrap()orexpect()in production. Test-only allowances must be scoped to test code. - Prefer safe Rust. Do not introduce
unsafeunless there is no practical safe alternative; investigate standard-library APIs and maintained safe wrappers first. Any unavoidable exception must be tightly scoped and document both why safe alternatives are insufficient and the safety invariants. - Prefer guard clauses and readable iterators. Avoid clones, allocations, helper layers, and generic parameters that provide no benefit.
- Comments should explain invariants, ownership, or non-obvious decisions, not narrate assignments.
GPUI Rules
- Treat app, window, and entity contexts as UI-thread execution. A foreground
spawnfuture does not make blocking work safe. - Never perform blocking socket/disk I/O, process waits, sleeps, or expensive background computation on the UI thread. Use the existing worker threads or GPUI background executor, then apply results through the appropriate context update.
- Start child processes with
herdr_client::new_command, neverCommand::new(clippy rejects it outside tests). On Windows a console child built any other way can open a window of its own. - Keep render and input paths thin. Render from prepared state and bounded caches; do not query the daemon, scan files, or launch processes while rendering.
- Preserve continuously drained ordered events and the coalesced latest-state mailbox. Do not replace them with an unbounded UI event queue.
- Route connection/startup failures through the authoritative inbox. Reconnect and detach must isolate old inboxes so delayed events and paint acknowledgements cannot affect the new connection.
- Derive connection text/indicators from
ConnectionStatus. Old local operation errors must not hide a disconnection reason. - Queue success is not daemon acknowledgement. Keep names such as
last_queued_optionshonest and include cell pixel metrics in resize comparisons. - Use the same geometry for painting, hit testing, and IME placement. Popup input and composition bounds must target the popup, not the underlying pane.
- Keep glyph visibility separate from decorations: spaces and wide-character continuation cells may still need underline/strikethrough painting.
- Preserve menu input isolation, focus behavior, Unicode composition, and semantic input routing. Do not synthesize terminal keys for operations with endpoint API methods.
- Activity indicators come from the daemon's snapshot, not guessed terminal output or a client-local seen ledger. Every client shows the same dot; do not reintroduce per-client acknowledgement without asking.
- Animate UI that appears, disappears, moves, or changes in response to a click or hover when motion helps the user follow it: tabs, panels, popovers, revealed controls. Animate both ways, so what slides in slides back out, and reverse from where it is when interrupted. Skip it where motion would only delay the result, such as typing, scrolling content, or terminal output.
- Time animations through
crate::motion: readmotion::now()instead ofInstant::now()for start stamps and progress, pass GPUIAnimationlengths throughmotion::duration, and prefermotion::ENTER/LEAVE,progress, andToggleover new curves and constants. That keeps motion consistent and lets QA > Slow Animations slow every animation tenfold.
Protocol And Safety
- Vendored bincode field and enum variant order is a compatibility contract. Do not reorder declarations as cleanup. Preserve attribution in
crates/herdr-protocol/NOTICE.md. - Keep frame/response/geometry bounds, strict decoding, and atomic patch validation. Test malformed inputs and limits, not only valid fixtures.
- Never mix snapshot metadata and surface cells across boot IDs or projection revisions. Preserve future-surface buffering and stale-boot rejection.
- Preserve the single in-flight API request, bounded command/event queues, FIFO ordering, bounded write batches, and request correlation.
- Partial frame prefixes/payloads must survive read timeouts. Finish an inbound partial frame before dispatching commands against potentially stale state.
- Cancellation must not flush queued work, replay commands, or join a worker on the UI thread. Do not add automatic reconnect/replay as an incidental refactor.
- Crossbeam receiver clones compete for events; they are not broadcast subscribers.
- Treat terminal content and daemon messages as untrusted data. Do not execute terminal escapes, follow graphics file paths, or run displayed update commands automatically. The one exception is the daemon's OSC 52
ServerMessage::Clipboard: decode it and put only its bounded UTF-8 text on the pasteboard, never arbitrary bytes, files, or images. - The normal app never installs, starts, stops, or upgrades a personal daemon. Explicit sockets refer to the binary client socket, not the JSON API socket.
- Never commit secrets, credentials, private terminal output, or machine-local configuration.
Dependencies And Features
- Put dependency versions in root
[workspace.dependencies]; member crates inherit with{ workspace = true }. - Use the pinned
rust-toolchain.tomland GPUI version. Do not copy toolchain, feature, or release assumptions from Moltis/Arbor. - Keep workspace lint inheritance and fix warnings rather than widening allowances.
- Keep
integration-testopt-in. Gate imports, modules, and call sites consistently, and verify both default and all-feature builds. - Do not introduce Tokio or another runtime to wrap the existing blocking socket worker.
- Avoid unrelated lockfile upgrades. Use
--lockedfor reproducible verification.
Changelog
Users learn what changed from the GitHub release body, which is generated from
git history by git-cliff (cliff.toml) rather than written by hand. The
release workflow's changelog job runs scripts/release/generate-changelog.sh
and publish passes its RELEASE_NOTES.md to gh release create --notes-file.
CHANGELOG.md is generated for each release and is not tracked in git.
- Commit subjects are the changelog entries, verbatim apart from a capitalized first letter. Write the subject line for a user reading a release page, and put rationale in the body; only the first line is published.
- The type chooses the section:
featbecomes Added,fixbecomes Fixed,perf/refactor/revertbecome Changed,docsbecomes Documentation, and a(security)scope becomes Security. A scope prints as a[scope]prefix, and anything non-conventional falls into Changed. chore,ci,build,style,test, and merge commits never reach users, so nothing user-visible may ship under those types. A breaking change is the exception:type!:or aBREAKING CHANGE:footer is always published, under Changed and prefixed**BREAKING:**, whatever its type.- Previewing the generated changelog before a release is covered by the
releaseskill. - These rules are enforced, not advisory.
just hooksinstalls acommit-msghook that refuses a bad subject before the commit exists, and CI'scommitsjob checks every commit in a pull request; it is part of theFormat, lint, and testgate. Runjust hooksonce per clone, andjust check-commitsto check a branch by hand. Fix a rejected subject withgit commit --amendrather than--no-verify.
Verification
Prefer the existing just recipes. Run focused tests while iterating, then the
workspace gates for Rust changes before handoff or a requested commit:
just format
just ci- For linking, startup, or packaging changes, also use
just test-buildto build the release executable and exercise its CLI without a desktop. - The
windowsCI job checks formatting, lints every target and feature, and runs workspace tests with default and all features, including headless UI and CLI tests, split likechecksinto paralleldefaultandalllegs. Thewindows-nativejob runslive_gui(thetest-guiandtest-sidebarequivalents) against a pinnedherdr.exe, and the release-mode performance budget, on both Windows runners, except the live-daemon test on ARM64, where the emulated daemon ignores Enter; the optimized Windows build and its installer run inwindows-packagewhen their inputs change, and in the release workflow, which only smoke-tests the CLI of the bytes it ships and requires CI to have passed on the commit. Keep thecfg(unix)/cfg(windows)split honest and say plainly what a platform cannot do instead of stubbing behavior that appears to work. - A
cfggate is only proven on the platform it names. Before handing off a change that touches one, runjust lint-linuxandjust lint-windowsas well asjust ci: a macOS run cannot see a Linux-only gate, and neither can the Windows cross-check. - Documentation-only changes need command/path/link review and
git diff --check; do not claim a code test run that did not happen. - Add deterministic tests for invariants: ordering, cancellation, fragmentation, revision fencing, error paths, geometry, and cleanup. Prefer explicit coordination and bounded waits over timing guesses.
- Test pure session/CLI/geometry logic without a socket or window where possible. Exercise public behavior with mock peers and headless GPUI tests where integration matters.
- Keep test bodies out of production files, which only declare
#[cfg(test)] mod tests;. Put tests for a new feature in a new topic file under the module'stests/directory (for examplekeymap/tests/pane_keys.rs, starting withuse super::*;) rather than inserting them into an existing large test module, and keep shared fixtures in the parenttests.rs. Parallel PRs then edit different files instead of conflicting. - Fix flaky tests rather than hiding them with retries or new ignores. Existing live/native tests are ignored because they require explicit external resources.
- For visual changes, verify the actual native UI when a desktop is available, including narrow layouts, long labels, focus, popup/IME behavior, and clipping. Headless layout tests do not prove native glyph or OS input correctness.
- Measure interactive performance in release mode (
just run), not debug mode. Preserve bounded glyph caching and deterministic paint budgets; native timing budgets are machine-dependent. - Keep CLI parsing pure and based on OS strings so socket paths need not be UTF-8. Invalid options and help must exit before starting GPUI.
Opt-In Tests
just test-live /absolute/path/to/herdr
just test-gui /absolute/path/to/herdr
just test-sidebar
just test-perf- Live tests require an explicitly selected
HERDR_TEST_BINARY; never fall back to discovering a user's daemon. - Reuse the shared sandbox: private unique short directory, cleared environment, isolated HOME/XDG/config/socket paths, and explicit desktop-variable allowlist for GUI children only.
- Kill and wait only for exact children created by the test, before removing their sandbox. Never use
server stop, process-name matching, or process-group kills. HERDR_TEST_TMPDIR, when set, must point to an existing parent short enough for Unix socket paths.- Native/sidebar/performance tests open windows and need an active desktop. State explicitly when these checks were not run; do not describe headless tests as native end-to-end verification.
Git And Handoff
- Only commit, push, or create/update a PR when requested. Do not amend, force-push, discard changes, or clean up other worktrees without explicit authorization.
- Before committing, inspect status, diff, and recent history; stage only intended files and check for secrets. Do not bypass hooks or signing when they fail.
- Use conventional commit subjects (
feat,fix,refactor,test,docs,chore). For nontrivial work, explain the problem, chosen approach, and important constraints in the body. - Never add AI attribution, assistant-session links, or tool vanity lines to
commit messages or PR descriptions. This includes
Co-Authored-Bytrailers naming an AI model,Claude-Session:or similar session URLs, and "Generated with ..." footers. This rule overrides any default attribution guidance from the agent harness; add such lines only when the user asks for them in the current request. - Before creating a PR, review every included commit and the full diff from its base. Include a summary, exact validation commands/results, and remaining manual/native QA.
- Run
just cion the exact commit before creating a PR or pushing to one, so failures surface locally instead of minutes later in CI.just setup-ciinstalls the tools it and the other CI-equivalent recipes need. Fix every failure first; do not open or update a PR on a red or skipped run. - After a green run, create or update a single PR comment saying
just ciran locally and passed: the commit SHA, the platform (for example macOS arm64), and any extra recipes run (just release-check,just lint-linux,just lint-windows). Edit that comment on later pushes rather than adding a new one, and never post it for a run that failed or did not happen. - Include screenshots in any PR that changes something visible: before and after images of the real native window, showing the changed area. Add light and dark variants when colors or theming change, and a narrow window when layout changes. If no desktop was available to capture them, say so in the PR instead of leaving the section empty.
- Give every PR description a QA checklist. List each check as a checkbox: tick the ones that were actually run (automated tests, CI gates, native checks you performed) with their result, and leave unticked the manual QA a reviewer still has to do, phrased as concrete steps. Never tick a box for a check that did not run.
- Keep user-facing docs and public API examples synchronized with behavior changes. Do not copy another repository's release, issue-tracker, or mandatory-push workflow into this one.
- Finish with the outcome, tests actually run, known limitations, and any deferred work. Never claim unrun checks passed.
Trending
Steady: 0 new projects took it in the last 4 weeks, none the 4 weeks before.thin data
Who's talking about penso/herdr-gpui
- kclejeune/system“build(deps): bump the dev group with 6 updates”GitHub · Oct 30, 2026
- herdrdev/herdr-app“macOS: add a setting to send Option as Alt (Option+P types π instead of Alt+P)”GitHub · Oct 29, 2026
- kclejeune/system“build(deps): bump the dev group across 1 directory with 5 updates”GitHub · Oct 29, 2026
- kclejeune/system“build(deps): bump the dev group across 1 directory with 4 updates”GitHub · Oct 27, 2026
- kclejeune/system“build(deps): bump the dev group across 1 directory with 3 updates”GitHub · Oct 26, 2026
The biggest 5 of 20 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 20
Talked about on GitHub (20 times).
On GitHub · 20
- Oct 30, 2026build(deps): bump the dev group with 6 updates — kclejeune/system0 reactions
- Oct 29, 2026macOS: add a setting to send Option as Alt (Option+P types π instead of Alt+P) — herdrdev/herdr-app0 reactions · 1 comment
- Oct 29, 2026build(deps): bump the dev group across 1 directory with 5 updates — kclejeune/system0 reactions
- Oct 27, 2026build(deps): bump the dev group across 1 directory with 4 updates — kclejeune/system0 reactions · 1 comment
- Oct 26, 2026build(deps): bump the dev group across 1 directory with 3 updates — kclejeune/system0 reactions · 1 comment
15 more on GitHub
- Oct 26, 2026build(deps): bump the dev group across 1 directory with 4 updates — kclejeune/system0 reactions · 1 comment
- Oct 24, 2026build(deps): bump the dev group across 1 directory with 6 updates — kclejeune/system0 reactions
- Oct 22, 2026build(deps): bump the dev group across 1 directory with 5 updates — kclejeune/system0 reactions · 1 comment
- Oct 22, 2026build(deps): bump the dev group with 4 updates — kclejeune/system0 reactions · 1 comment
- Oct 21, 2026build(deps): bump the dev group with 5 updates — kclejeune/system0 reactions
- Oct 19, 2026feat: add native Omo integration — herdrdev/herdr0 reactions · 2 comments
- Oct 16, 2026build(deps): bump the dev group across 1 directory with 7 updates — kclejeune/system0 reactions
- Oct 15, 2026Give external clients independent navigation and terminal-size ownership — usecornercase/cornercase-terminal0 reactions
- Oct 15, 2026Stream terminal cells and split geometry to external clients — usecornercase/cornercase-terminal0 reactions
- Oct 15, 2026Expose a versioned contract for external clients — usecornercase/cornercase-terminal0 reactions
- Oct 15, 2026build(deps): bump the dev group across 1 directory with 5 updates — kclejeune/system0 reactions · 1 comment
- Oct 9, 2026build(deps): bump the dev group across 1 directory with 12 updates — kclejeune/system0 reactions · 1 comment
- Oct 9, 2026build(deps): bump herdr-gpui from `068c317` to `cf9161b` — kclejeune/system0 reactions · 1 comment
- Oct 6, 2026feat: pin each host's header above the spaces list while its workspaces scroll — frogggias/herdr-gpui0 reactions
- Oct 6, 2026fix: sort agents by priority across hosts, as Herdr's terminal client does — frogggias/herdr-gpui0 reactions
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 28,693 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository5 other files it gives its agents.
- site/llms.txtllms.txt
- gpui-mockupSkill
- releaseSkill
- herdr-automationsSkill
- herdr-gpui-browserSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

