Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Harness ops

How to inspect, install, and repair this runtime (agent + host pool). Use when tools fail, hosts look wrong, or the user asks you to update myco / explain the harness.

Host PATH prerequisites

Same executables as the README Install section (extra binaries on PATH). Install on each machine that runs the agent and/or host tools; remotes need what their host tools spawn, not only the agent laptop.

Required

  • ssh — attaches remotes (ssh … myco --mode host over NDJSON) and is used for install/diagnose over SSH.
  • uv — hermetic Python runs (agent computer-use norm: scripts and deps without polluting the system).
  • bash — host bash tool (one-shot exec and multi-turn shell sessions).

Recommended

  • git — worktrees/branches, repo inspection, and git archive when shipping local source to remotes.
  • gh — GitHub CLI for PRs, issues, and release workflows the agent often drives.
  • curl — downloading release source tarballs.
  • ck — semantic / hybrid code search (cargo install ck-search); agents use it via bash where installed, alongside rg.

Also needed when building from source: stable Rust / cargo (and curl as above).

Finding configured hosts

  • Local is always present (in-process); it is never configured.

  • Remotes are the concrete Host aliases in ~/.ssh/config (Includes are followed; wildcard */? and negated ! patterns are ignored; alias local is reserved). Host name == alias == SSH destination.

  • ~/.myco/profiles/default/config.toml (or $MYCO_CONFIG / myco --config) holds knobs only: attach_timeout_secs, host_idle_timeout_secs, max_prelude_bytes.

  • Read ~/.ssh/config with tools when you need remote names or SSH destinations.

  • Connection sharing: each session runtime opens its own ssh <alias> myco --mode host worker per remote it touches. OpenSSH can multiplex the SSH transports over one authenticated connection per host; the tool workers and their owned resources still remain separate:

    Host *
        ControlMaster auto
        ControlPath ~/.ssh/cm-%r@%h:%p
        ControlPersist 10m
    
  • Idle workers: host_idle_timeout_secs defaults to 1800 (30 minutes); 0 disables reaping. Unused connections with no outstanding calls or retained processes/output close automatically and reconnect on the next host= call. Inventory polls do not keep them alive. Close unused bash handles explicitly, including exited processes whose output is still retained. Editor read fingerprints expire with the connection; read the file again before editing after reconnect. Each host worker uses two async runtime threads; blocking I/O may use additional threads while needed.

  • Resource ownership: reusable shells survive user turns, live compaction, and archival. Archival changes visibility; it does not cancel active work or discard retained handles. Reaping applies to archived sessions under the same rules. Ending the owning runtime releases its tools.

  • Lazy connection status: “connects on first tool use” is normal, not an outage. Runtime records report the last failure timestamp; live status also shows its age. After a transport failure, retry host=<alias> once before falling back to raw SSH. If the previous call may have changed something, inspect its effects before repeating that command.

  • Call timeouts: one missing tool response requests cancellation of that call and probes the worker. A responsive worker keeps its connection and other bash sessions. A failed health check resets the connection and reports lost remote sessions using the last available inventory (which may be incomplete).

  • No pseudo-terminal: bash action=start uses pipes on local and remote hosts. Prefer host=<alias> with command: "bash" or "bash -l" for long-lived remote shells. Many allocators and REPLs work without a TTY; check their noninteractive options before using ssh -tt. Programs that require a controlling terminal or job control are not supported by these pipe sessions.

  • Shell handles: an in-flight operation keeps its original input/output and owner even if another shell reuses the same handle name. Closing or reaping a handle still stops its process group while reads or writes are outstanding.

  • Shell cleanup: closing a retained bash handle, ending its owning runtime, or gracefully shutting down its host kills the owned process group, including children that outlive the shell after redirecting their output. An exited shell remains waitable until the handle closes, reserving its process-group identity for safe cleanup; close unused handles to release that process-table entry. Children that deliberately leave the process group (for example with setsid) are outside this ownership boundary. Ordinary one-shot exec completion retains its existing behavior.

  • Inspect tool errors and use the SSH checks below to diagnose remote attachment.

  • Host tool field host must match a configured name (local or a remote name). Omitted → local.

Updating / installing myco

Local uses the agent process binary / in-process worker — rebuild/reinstall the interactive myco on this machine and restart the server.

For remotes, prefer a same-platform binary (release asset or build on the target) when you are not actively developing myco; only build from a local git tree when you are working on the myco codebase itself (unreleased commits, dirty worktree, or a feature branch that must ship). Do not scp/rsync a prebuilt binary across mismatched OS, CPU arch, or glibc (e.g. newer glibc → older cluster fails with GLIBC_X.Y not found); for those targets, compile on the machine or use a matching release.

Choose: release snapshot vs local source tree

  1. Inspect the running agent binary (this process):
    • session_meta with action: "executable_path" → absolute path of the agent myco.
    • Then via bash: "$path" --version (package version from clap / CARGO_PKG_VERSION).
  2. If you are currently working on myco (cwd is a myco checkout, or the user asked to deploy local unreleased changes): build from that git tree (see Snapshot the repo below) so remotes match the working tree.
  3. Otherwise (normal install / update): download a source snapshot from GitHub Releases for the version you want (usually the same as the local binary's --version, or a newer release the user named):
https://github.com/tsnl/myco/releases

Typical assets / URLs (GitHub):

# Prefer the release tag that matches (or is newer than) local `myco --version`.
# Source tarball for tag v0.1.0 (example):
VER=0.1.0
curl -fsSL -o /tmp/myco-src.tgz \
  "https://github.com/tsnl/myco/archive/refs/tags/v${VER}.tar.gz"
# Or the auto "Source code (tar.gz)" asset on the release page for that tag.

Unpack on each remote and cargo install there (next section). If no suitable release exists yet, fall back to archiving the local git tree.

Snapshot the repo (local git tree only)

Use this when deploying work-in-progress or unreleased commits from a myco checkout.

From the myco git root, create a source snapshot with git archive (tree only — tracked files at a commit/tree; not untracked files, and not uncommitted dirty work unless you archive a commit that includes them):

# Clean committed snapshot of HEAD (usual case):
git archive --format=tar.gz -o /tmp/myco-src.tgz HEAD

# Include current dirty tracked changes: temporary tree object, then archive it:
REF=$(git stash create)   # empty if worktree is clean — fall back to HEAD
git archive --format=tar.gz -o /tmp/myco-src.tgz "${REF:-HEAD}"

git archive is the right “tarball of this repo state” tool. Commit (or use git stash create) first if the install must include uncommitted edits. Untracked files are never in the archive; add/commit them if they are required to build.

A release only needs platform-matched binaries. Do not scp binaries across mismatched OS/arch/glibc; for those hosts, build there or use a matching release asset. Builds are fully offline beyond the crates.io dependency fetch.

Install on each remote host (build from source)

HOST=devbox   # Host alias from ~/.ssh/config (== myco host name)
# /tmp/myco-src.tgz is either a GitHub release source tarball or a local git archive.
scp -o BatchMode=yes /tmp/myco-src.tgz "$HOST:/tmp/myco-src.tgz"
ssh -o BatchMode=yes "$HOST" 'set -euo pipefail
  rm -rf ~/src/myco-src ~/src/myco-src-extract
  mkdir -p ~/src/myco-src-extract ~/.local/bin
  tar -xzf /tmp/myco-src.tgz -C ~/src/myco-src-extract
  rm -f /tmp/myco-src.tgz
  # GitHub release tarballs nest under myco-<tag>/; `git archive` is usually flat.
  entries=(~/src/myco-src-extract/*)
  if [ ${#entries[@]} -eq 1 ] && [ -d "${entries[0]}" ]; then
    mv "${entries[0]}" ~/src/myco-src
    rmdir ~/src/myco-src-extract 2>/dev/null || rm -rf ~/src/myco-src-extract
  else
    mv ~/src/myco-src-extract ~/src/myco-src
  fi
  export PATH="$HOME/.cargo/bin:$PATH"
  command -v cargo >/dev/null || { echo "cargo/rustc required on host"; exit 1; }
  cargo install --path ~/src/myco-src --force --locked --root "$HOME/.local"
  # ~/.local/bin is the usual remote install path in multi-host setups
  ~/.local/bin/myco --version
'
  • Require Rust/cargo when building from source. Prefer a prebuilt same-platform binary when available.
  • Remotes need myco on the remote PATH used by non-interactive SSH (BatchMode); ~/.local/bin or ~/.cargo/bin are common — verify with ssh -o BatchMode=yes <alias> 'command -v myco; myco --version'. An interactive login can resolve a different binary; check the non-interactive command used by the worker.
  • After replacing binaries, the server must be restarted to load a new agent binary; remote host workers respawn on next tool use.
  • Ask before destructive remote installs; prefer installing into user prefixes (~/.local, ~/.cargo) over system paths.

Diagnosis checklist

When tools fail or the user asks why something is broken, investigate with tools:

  1. Host down / unavailable

    • Local never needs a host subprocess; if local tools fail, debug the agent process itself.
    • Read ~/.ssh/config for Host aliases (remote names == destinations); the selected profile's config.toml (or $MYCO_CONFIG) only for knobs.
    • On remote: ssh -o BatchMode=yes <alias> 'command -v myco; myco --version' via the local host's bash. Compare that path and version with the expected install; connection requires matching package and host-protocol versions. A protocol mismatch names the host to rebuild before tool calls can run. Host protocol 5 includes skills in the standard host catalog; older workers must be rebuilt before use, even when the package versions match. Each call also carries its selected model image limit. A missing call limit retains the worker startup ceiling; no call can raise that ceiling. An interactive login may use a different PATH. If missing/outdated: install a binary built for that platform (matching release asset), or build on that host from source. Do not copy binaries across mismatched OS/arch/glibc.
    • Confirm SSH alias works: ssh -o BatchMode=yes <alias> true.
    • Startup checks expected executables on the agent machine (bash, ssh/ssh-add/ssh-keygen when remotes are configured) and reports missing ones in the startup WARNING block — the user must install them and restart myco. Remote hosts report missing programs as tool errors at call time.
    • If auth fails with BatchMode: check ssh-add -l and the startup ssh-agent preflight (silent when clean; problems open a WARNING block before the first USER block). Unlock with ssh-add / ssh-add --apple-use-keychain <key> (myco cannot prompt on the NDJSON pipe). Restart myco after loading keys.
    • Retry the tool after fixes; restart the server if its configuration changed.
  2. Wrong machine / wrong files

    • Check whether host was set; default is always local.
    • bash uname -n / pwd / hostname on the intended host.
    • For missing skills, call skills with the intended directory and host. Relative paths use the worker's launch directory, even after a bash cd. Check .agents/skills, .claude/skills, or .grok/skills in that directory, its ancestors through the nearest Git root, and that host user's home. Outside Git, ancestors are not scanned. Each skill needs its own directory and a regular SKILL.md with name and description frontmatter.
    • Read discovery warnings: symlinks, malformed metadata, unreadable paths, and scan limits can exclude entries. Explicit discovery refreshes the catalog; successful file operations also discover their operated directory. Read a selected skill with the editor on the same host. Identical names in different paths remain distinct skills.
  3. Session / state confusion

    • Conversation resume ≠ restored bash sessions or editor state.
    • Bash sessions die when the host process exits (server exit, host crash, SSH drop). Local in-process sessions die with the agent process.
  4. Explain product limits honestly

    • Remote health is checked after a missed call deadline; local is always in-process.
    • Cancellation is forwarded over the host pipe. A lost acknowledgement leaves effects unknown; inspect state before repeating work.
    • You cannot invoke slash-commands; tell the user which to run.

When helping the user change config, prefer surgical edits to ~/.ssh/config (hosts) or ~/.myco/profiles/default/config.toml (knobs) and show a minimal diff. Ask before destructive remote installs.