nova-friend

command
v1.4.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 16, 2026 License: MIT Imports: 33 Imported by: 0

README

nova-friend

What it is

nova-friend: what a friend runs to be part of the team: the lanes that work the friend's cards and their sprint metadata beat

Why use it

Work as a friend: the friend's cards run in lanes and messages reach the session. Liveness is not this tool's: it is the nova-hook record's (nova-hook hook, nova-hook prove).

Install

go install github.com/mas-bandwidth/nova-tools/cmd/nova-friend@latest
nova-friend version

First run

The transcript below is executed line for line by the docs tests; the full record is in docs/TESTS.md.

Run by cmd/nova-friend/firstrun_test.go on a throwaway redis-server whose friends set names ada and bob (what nova-config apply writes for two friend rows), its address in NOVA_BUS_REDIS, so the lines read as a reader types them. The sitting is the canary by hand, with no daemon running: a dry-run install prints the plan for bob's agent; a dry-run uninstall the plan to undo it; bob's session answers a reach step's nonce with pong (one note to ada on the bus, from bob's own stream); status says no daemon has run as bob (exit 1). ./ is a directory of the test's own, and so are the home directory and the uid the plan names. The run-owned values are the message id= (a ULID from the store's time) and at=.

$ nova-friend install --as bob --harness opencode --dir ./bob --model deepseek/deepseek-v4 --dry-run
INSTALL OK label=com.nova.friend-bob plist=./home/Library/LaunchAgents/com.nova.friend-bob.plist launchd_log=./home/Library/Logs/nova-friend-bob.log dry_run=true
INSTALL PLAN command="write ./home/Library/LaunchAgents/com.nova.friend-bob.plist"
INSTALL PLAN command="launchctl bootout gui/501/com.nova.friend-bob"
INSTALL PLAN command="launchctl bootstrap gui/501 ./home/Library/LaunchAgents/com.nova.friend-bob.plist"
INSTALL NOTE the agent runs: nova-friend run --as bob --harness opencode --dir ./bob --width 0, with --redis and --server as given here

$ nova-friend uninstall --as bob --dry-run
UNINSTALL OK label=com.nova.friend-bob plist=./home/Library/LaunchAgents/com.nova.friend-bob.plist dry_run=true
UNINSTALL PLAN command="launchctl bootout gui/501/com.nova.friend-bob"
UNINSTALL PLAN command="rm ./home/Library/LaunchAgents/com.nova.friend-bob.plist"

$ nova-friend pong --as bob --nonce abc123 --to ada --queue 2 --working 1 --width 4
PONG OK nonce=abc123 to=ada id=01M42EJZ1F8FXB5T0F6EXJCRS1 at=2026-10-04T03:40:12Z

$ nova-friend status --as bob --dir ./bob
! STATUS NONE: no daemon has run as bob (no status file in ./home/.nova-friend/bob); run: nova-friend install --as bob --harness <h> --dir ./bob

Verbs

The nova-friend section of the command reference documents every verb's flags, effect and exit codes.

  • run
  • install
  • uninstall
  • check
  • host
  • pong
  • status
  • refuse-go
  • resume
  • version
  • help

Spec

The contract is docs/SPEC-FRIEND.md.

Every run has a spend cap per day and per provider, read from its config ($20/day by default, friend.DefaultSpendCapUSD); at the cap the daemon stops launching turns and raises one judgment to the seat and the owner, and a provider refusal for funds (an insufficient balance, a 402) stops its turns at once with the same judgment. Spend is measured from the harness's own usage report, never estimated. A daemon whose friend has no dealt work and no live session does not launch turns at all (docs/SPEC-FRIEND.md, a-friend-daemon-has-a-spend-cap-and-stops-at-a-provider-refusal.w1).

Documentation

Overview

The daemon's reading of every harness's credit and quota refusal, from the places a lane leaves it: the lane's stdout, its stderr, the harness log it writes and the REPORT.md it leaves (docs/SPEC-FRIEND.md, a harness out of credits). One table names each harness's 402 and its own wordings, so a friend is marked down for every harness it runs, never only for the ones whose wording is already known. A refusal no row knows is never silently retried: three lanes ending with the same first error line surface to the seat as one judgment, "lanes failing alike: <line>".

This file is pure: no store, no socket, no real time; the tests step it with an injected clock.

nova-friend is what a friend runs to be part of the team (docs/SPEC-FRIEND.md; the model is tla/Friend.tla): one launchd agent per friend that parks on the friend's nova-bus stream and pushes each message into the running session as a turn, runs the one-shot lanes that work her sprint cards, and beats to the sprint server, whose answer carries her row. Liveness is the nova-hook record's alone (cmd/nova-hook); the coordinator's ping verbs and keepalive loop are retired (v1.3.5, internal/ci retired_presence_class_test.go). The verbs are run, install, uninstall, check, status, pong, watch, host, reach, lanes, resume and acceptance; the dispatch, the banner, the help, the refusals and the output envelope are pkg/tool's, and the rules are pkg/friend's.

The lane fault a provider's refusal leaves, as nova-friend status and nova-friend lanes report it: lane-fault=<n> refusal="<first line>", read from the fault file the daemon writes in the state directory (docs/SPEC-FRIEND.md, the lanes). A provider refusal is terminal: the daemon holds the lane and says so here until a person clears it or the daemon restarts.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL