Claude Code (>= 2.1.277) and opencode both read AGENTS.md, but Claude
Code reads it only when no CLAUDE.md exists in its cwd or above. So
this is a plain rename with no CLAUDE.md stub left behind.
- hive-agent/src/agents_md_migrate.rs: new. At harness start, before
the first turn, renames state/CLAUDE.md to state/AGENTS.md when only
the former exists; logs an error naming both paths when both exist
and touches neither; does nothing otherwise. Idempotent.
- hive-agent/src/main.rs: calls it in serve_main; checkpoint prompt
and a comment name AGENTS.md.
- hive-agent/src/claude_md_watch.rs: the size watch reads AGENTS.md;
todo text, doc comments and tests follow. Module name, todo
subsystem key ("claude_md") and metric name
(hyperhive.agent.claude_md.lines) are unchanged so existing todo
rows and dashboard history carry over.
- hive-agent/src/turn.rs, hive-agent/prompts/system.md: prompts tell
the agent its file is AGENTS.md.
- hive-agent/src/{otel_turn_metrics,stats}.rs,
frontend/packages/agent/src/stats.js, hive-subagent-mcp/src/*.rs:
comments and a tool parameter description naming the agent's file.
- nix/host-modules/swarm-grafana/dashboards/agents.json: panel title
and description.
- claude-plugins skills claude-subagents, state-hygiene: they mean the
agent's own state file.
- CLAUDE.md -> AGENTS.md at the repo root; docs/crates/README.md link
(checked by check-doc-refs.sh), hive-c0re/README.md,
.prettierignore and the nix/sources.nix comment follow.
- docs/: every prose mention of the agent's file; persistence.md
documents the boot-time rename, claude-invocation.md the shadowing.
Fixes #5509
69 lines
2.8 KiB
Rust
69 lines
2.8 KiB
Rust
//! The per-agent paths this daemon needs.
|
|
|
|
use std::path::PathBuf;
|
|
|
|
/// The harness-served in-agent todo socket (loose-ends v2). This daemon
|
|
/// pushes exactly one todo per subagent lifetime — the completion summary,
|
|
/// once its background turn finishes. Override via `HIVE_AGENT_SOCKET`;
|
|
/// same resolution as `hive-bash-mcp`'s own `paths::agent_socket`.
|
|
#[must_use]
|
|
pub fn agent_socket() -> PathBuf {
|
|
std::env::var_os("HIVE_AGENT_SOCKET").map_or_else(
|
|
|| PathBuf::from(hive_agent_sock::DEFAULT_AGENT_SOCKET),
|
|
PathBuf::from,
|
|
)
|
|
}
|
|
|
|
/// Durable state directory for the current agent. Same resolution as
|
|
/// `hive-agent`'s own `paths::state_dir` — reads `HYPERHIVE_STATE_DIR`
|
|
/// (always injected via `systemd.globalEnvironment` by the meta flake),
|
|
/// falling back to the `HIVE_LABEL`-derived pattern for dev/test
|
|
/// environments where the env var may not be set. Copied rather than shared
|
|
/// with `hive-agent` (a binary crate with no lib target) — a five-line env
|
|
/// read isn't worth a crate dependency to dedupe.
|
|
#[must_use]
|
|
pub fn state_dir() -> PathBuf {
|
|
if let Some(p) = std::env::var_os("HYPERHIVE_STATE_DIR") {
|
|
return PathBuf::from(p);
|
|
}
|
|
let label = std::env::var("HIVE_LABEL").unwrap_or_default();
|
|
PathBuf::from(format!("/agents/{label}/state"))
|
|
}
|
|
|
|
/// The agent's persistent work dir, a sibling of [`state_dir`]
|
|
/// (`/agents/<name>/work`). It has no `AGENTS.md` above it, so a subagent
|
|
/// started here does not load the agent's own.
|
|
#[must_use]
|
|
pub fn work_dir() -> PathBuf {
|
|
state_dir().with_file_name("work")
|
|
}
|
|
|
|
/// The working directory a subagent gets when `start` is given no `dir`:
|
|
/// [`work_dir`] when it exists, else `None` (the daemon's own cwd). The
|
|
/// directory only exists once the container has restarted with its bind, and
|
|
/// a spawn into a missing cwd fails with a bare ENOENT.
|
|
#[must_use]
|
|
pub fn default_cwd() -> Option<PathBuf> {
|
|
Some(work_dir()).filter(|p| p.is_dir())
|
|
}
|
|
|
|
/// Where this agent's named subagent role files live, one markdown file per
|
|
/// role under the agent's own [`state_dir`]. Per-agent rather than
|
|
/// hive-wide: the clauses a role carries came out of one agent's own prompt
|
|
/// files, and this daemon only ever spawns on behalf of that agent. The
|
|
/// directory is a convention, not a registry — it is created by whoever
|
|
/// writes a role into it, and its absence simply means this agent ships no
|
|
/// roles yet (see `crate::role`).
|
|
#[must_use]
|
|
pub fn subagent_roles_dir() -> PathBuf {
|
|
state_dir().join("subagent_roles")
|
|
}
|
|
|
|
/// Harness-internal scratch dir this daemon writes its own generated
|
|
/// subagent `--mcp-config` file into (see `crate::mcp_config`). Delegates to
|
|
/// the shared resolver so this and `hive-agent`'s own harness dir always
|
|
/// agree on the same path.
|
|
#[must_use]
|
|
pub fn harness_dir() -> PathBuf {
|
|
hive_agent_sock::paths::harness_dir()
|
|
}
|