Skip to content

feat: delete the full-screen interface - #86

Merged
nicodes merged 6 commits into
mainfrom
feat/delete-the-interface
Aug 8, 2026
Merged

feat: delete the full-screen interface#86
nicodes merged 6 commits into
mainfrom
feat/delete-the-interface

Conversation

@nicodes

@nicodes nicodes commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Closes nicodes/komizo-be#55. Step 9 of nicodes/komizo-be#46, and the only irreversible one.

12,302 lines deleted, 406 added. Thirteen tui_*.go files, the tests that drew them, and every terminal-UI dependency in go.mod.

Nothing loses a capability, and one thing gains one

The parity rule is that the CLI can do everything over SSH. Checking that meant reading what the interface knew that no command did, and there was one: whether the agent on a box is behind this komizo.

komizo report printed the box's version and stopped. Comparing it required knowing this binary's own version, which is not something a reader has. The interface's server row did the comparison and the command did not, so deleting it would have deleted the answer. agentBehind now says it and names the remedy:

root@box -- alpine, ready
  komizo 0.0.1, agent 0.0.16
warning: this box was set up by komizo 0.0.1; this is 0.0.16.

    komizo update --host root@box

Both signals are kept because each catches what the other misses: a different stamp means the agent binary differs (the version misses this the whole time a build calls itself dev), and a different version means something else komizo installs changed — a script, a doas rule — which the stamp misses whenever the changed thing is not the agent.

The parity test was a list, and a list is what let the original bug through

parity_setup_test.go held two hardcoded rows: init.go and tui_ops.go. The bug it was written for was that the interface's setup path never registered the server — and that path only got caught because somebody added it to the list by hand. A third path would have passed vacuously.

It now walks the package with go/ast, finds every function that runs the provisioning script, and pins the set. A new setup path goes red before any of the "each path must also do X" rules get a chance to be vacuously true about it.

Two constants came back to the model they belong to

  • devLimit clamps a deviation score. It lived in the monitor screen, where it also happened to be the top of a y axis — but it decides a number this package computes, so it is in metrics.go.
  • chartWindow is the default range every signed read resolves, now defaultWindow in timerange.go.

Entry points

Bare komizo prints its help and exits 0 — asking a tool what it does is not a misuse of it, and komizo || echo broken should not call it broken. A bare address names where the work moved rather than answering with thirty lines of usage.

Checks

Five mutations against the new capability, all red:

caught  printReport never calls agentBehind
caught  the stamp comparison is dropped
caught  the version comparison is dropped
caught  a version-less box is treated as current
caught  every box is told it is behind

The last one matters: the first four are all satisfied by printing the warning unconditionally, which would put it on every healthy box.

go build, go vet, gofmt -l and go test ./... -count=1 are clean — exit 0, checked rather than eyeballed.

Left deliberately

lifecycle.go's comments still say "these existed ONLY in the interface". That is accurate history — one of them anticipates this deletion — and rewriting it to have always been so is what the house style says not to do.

nicodes and others added 3 commits August 7, 2026 22:43
Step 9 of nicodes/komizo-be#46, and the only irreversible one. Refs
nicodes/komizo-be#55.

The app is the product now, so the interface is thirteen files and the
tests that drew them. What is NOT deleted is any capability: the parity
rule is that the CLI can do everything, over SSH, and one thing only the
interface knew has moved rather than gone -- whether the agent on a box is
behind this komizo. `komizo report` printed the box's version and left the
comparison to a reader who would have to know this binary's own version to
make it; agentBehind now says it and names the remedy.

Two constants came back with the data model they belong to: devLimit is a
clamp on a deviation score, not the top of an axis, and chartWindow is the
default range every signed read resolves, now defaultWindow.

parity_setup_test.go was a hardcoded list of two surfaces, and a list is
what let the original bug through -- the interface's path simply was not on
it. It now walks the package with go/ast, finds every function that runs
the provisioning script, and pins the set, so a third path goes red rather
than passing vacuously.

Bare `komizo` prints its help and exits 0; a bare address names where the
work moved rather than answering with thirty lines of usage.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
go.mod loses every terminal-UI dependency with it -- bubbletea, lipgloss,
bubbles, ntcharts and their transitive set, 31 lines of module and 54 of
sum. Fewer dependencies in the binary that holds an SSH key to other
people's servers is the part of this worth saying out loud.

The update help no longer cross-references a keystroke. It named `"u"`,
which was the honest reference while there were two surfaces and is now
advice that works only if you are looking at a program that does not
exist; it names `komizo report` instead, which is what tells you a box is
behind. Its test required the old string, so that moved with it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@nicodes

nicodes commented Aug 8, 2026

Copy link
Copy Markdown
Owner Author

Review 1

Request changes. The agentBehind port is correct and genuinely guarded — all five mutations the PR body claims, plus a sixth of my own, go red. But the parity sweep that found one gap missed several, and two of them are worse than a missing read: they turn a settings edit into a credential rotation that breaks the repo's next deploy.

Reviewed at b41e1c9, in a detached worktree off the PR head. Every mutation below was applied, run, and reverted; the tree is back at b41e1c9 with git status --porcelain empty.

Baseline (item 7), exit codes checked rather than eyeballed

go build ./...            exit 0
go vet ./...              exit 0
gofmt -l .                exit 0, no output
go test ./... -count=1     exit 0
go test ./... -count=1 -race  exit 0   (what CI runs)

docs/checks.md does not exist anywhere in this repo or in komizo-be — I applied the standard as stated. Worth filing separately.

What holds up

agentBehind (item 1) is faithful to the deleted komizoServerLine/komizoOutOfDate, and every branch is load-bearing:

RED  M1  printReport never calls agentBehind
RED  M2  the stamp comparison is dropped
RED  M3  the version comparison is dropped
RED  M4  a version-less box is treated as current
RED  M5  every box is told it is behind
RED  M6  the not-installed remedy changed from init to update

M6 is mine and it matters: the remedy string is asserted, not just the sentence. The one case-by-case difference from the interface — !Installed now names komizo init where the interface's row said "u to install", i.e. update — is a defensible reading and the box script agrees, so I am not raising it.

Four of the five setupPaths guards also hold (details in blocking #8).


BLOCKING

1. komizo remove tells the user to run the invocation this PR deleted

internal/app/remove.go:40-43 is untouched by this diff. Against the binary built from this branch:

$ komizo remove --host root@box --app blog
error: this deletes /srv/blog, its volumes, its deploy account and its rules.
    Other apps on the box are untouched, and images stay in your registry.
    Re-run with --yes if that is what you want, or use the interface:
        komizo root@box

$ komizo root@box
error: "root@box" is not a command.

The PR body says a bare address "names where the work moved rather than answering with thirty lines of usage". It does — but komizo's own error text still sends people there. This is the one entry-point check that fails item 5.

2. Changing an app's config image now rotates its deploy key

The interface's c ran doAddKeepingKey and said so on the result screen: "Nothing in GitHub changed — the deploy key and host keys are the same." The machinery for that survives end to end. addPlan.keepKey still exists (internal/app/add.go:213), performAdd still honours it (add.go:253), and the box script explicitly supports it (scripts/alpine.sh:247-252):

An empty CI_PUBKEY means "leave the deploy key alone", which is what a setting change wants: re-running this to re-point an app at a different config image must not issue the repo a new key it does not know about.

What is gone is the only caller. Non-test producers of keepKey:

$ grep -rn keepKey --include='*.go' . | grep -v _test
internal/app/add.go:209:  // keepKey leaves the account's existing authorized_keys alone. ...
internal/app/add.go:213:  keepKey bool
internal/app/add.go:253:  if p.keepKey {

None. RunAdd builds its plan without it (add.go:163-173), so komizo add --config NEW always generates a fresh keypair. The consequence is not a missing read — pointing an existing app at a new config image now invalidates that repo's KOMIZO_DEPLOY_KEY and its next deploy fails until somebody pastes a new secret. komizo update is not the alternative: it keeps the key (refresh.go:266 sends an empty CI_PUBKEY) but reads the image back off the record and cannot change it.

One flag on komizo add closes this.

3. An app's known-as list can be added to but never cleared

The interface's a prompt said in as many words: "Comma-separated, and empty is an answer." It passed clearKnownAs. Non-test producers:

$ grep -rn clearKnownAs --include='*.go' . | grep -v _test
internal/app/add.go:201:  // clearKnownAs says the empty knownAs above is an answer rather than a
internal/app/add.go:205:  clearKnownAs bool
internal/app/add.go:284:  "CLEAR_KNOWN_AS": boolEnv(p.clearKnownAs && len(p.knownAs) == 0),

None. So komizo add --known-as "" sends CLEAR_KNOWN_AS=0, and scripts/alpine.sh:223-234 reads an empty KNOWN_AS with the flag off as "unchanged" and restores the recorded value. Removing a name from the pinned set has no command. (And per #2, the edits that do work rotate the key.)

4. An app's KOMIZO_KNOWN_HOSTS can no longer be read without rotating its key

The interface's h copied exactly this value for the selected app, using formatKnownHosts(m.tgt.namedFor(names), m.srv.hostKeys), and touched nothing. Now formatKnownHosts is reachable only through printNextSteps, which is called only from RunAdd. komizo list and komizo report never print a known_hosts line; --json gives server.host_keys as {type, key} pairs — the ingredients, not the value CI pins, and not scoped to the app's names. Re-pasting a KOMIZO_KNOWN_HOSTS that was lost now costs a key rotation.

5. Volumes are gone from every command

The interface had two views: an app's per-volume sizes ("Volumes", measured on open, shared volumes counted once under the first mounter) and the box-wide "Volumes by app". After this PR:

$ grep -rn -i volume --include='*.go' internal/app/ | grep -v _test | grep -v '^\S*:[0-9]*:\s*//'
internal/app/report.go:282, 289   (volumesFromBox)
internal/app/remove.go:23, 40, 101 (--keep-data wording)

komizo report's flags are host/port/accept-host-key/json/cached and it sends ["report"] (report_cmd.go:29-33,48) — there is no --volumes. volumesFromBox, volTotal, storageSeries and mountsIn all have zero non-test callers (deadcode output below). The only route left is running komizo-box report --volumes on the box by hand, which contradicts the usage text this PR just wrote: "komizo runs on your machine and connects to the box itself; you never run anything on it by hand."

6. The box's processor usage is gone

printReport prints memory and disks and nothing else (report_cmd.go:152-163). Neither report_cmd.go nor list.go contains the word "cpu" or "processor" outside comments. System.CPU is cumulative jiffies, so a figure needs the two-reading arithmetic in boxCPUAt/cpuSeries — both now unreachable. The interface showed a processor bar with the core count beside it; no command answers "is this box busy".

7. Requests served and 5xx counts are gone

No komizo subcommand ever asks the agent for metrics: RunReport sends ["report"], RunList sends ["report"]. metricsFromBox, seriesFor, seriesForBox, seriesForService, servesAnyHostname have no non-test caller. The counts exist on the wire (komizo-box poll|monitor --from --to) but nothing in the CLI requests them. Charts are presentation and I am not asking for charts back — "how many requests did this app serve" and "how many of them failed" are information, and there is now no command that will say.

If the intended answer is "the app shows that", then the parity rule as written needs amending in the same PR that stops honouring it, not silently.

8. The pin test that replaced the parity list can be walked past two ways

This is the guard the PR nominates as the structural fix, and refresh_test.go's now-one-row table explicitly defers to it ("A second update path cannot appear without going red there first"). Four mutations confirm it works:

RED  P1   a new function calling scripts.AlpineInitScript directly
RED  P3   RunUpdate no longer installs the agent
RED  P4   RunInit no longer registers the box
RED  P6   setupPaths can no longer find the script (the guard's own guard)
RED  P5b  registering becomes fatal (plain return in the branch)

Two do not:

GREEN  P2  a new setup path whose script reference is a package-level var
GREEN  P8  a real setup path whose runner method name starts with "Print"

P2 is the original bug's exact shape. setupPaths only walks fn.Body, so this is invisible to it and every "each path must also do X" rule is vacuously true of it:

var provisionScript = scripts.AlpineInitScript

func RunProvisionThree(t target) error {
	return t.runScript(provisionScript, nil)
}

Suite stays green. P8 is isPrintArg (item 2): it accepts any selector whose name starts with Print, without checking the receiver is fmt, so shRunner.PrintAndRun(scripts.AlpineInitScript) is exempted as though it were komizo script init. Yes, it is a real setup path being wrongly exempted — which is the direction that matters.

The same looseness fails the other way too: rewriting remove.go's fmt.Print(scripts.AlpineInitScript) as fmt.Fprint(os.Stdout, ...) makes the pin test go RED, because Fprint does not start with Print. A refactor with no behavioural change breaks the guard.

Matching on the declared type of the runner, or on "is this value ever passed to something that is not a printer", would close both.

9. The box still tells operators to press a key in the interface

$ grep -n interface scripts/alpine.sh
1092:	echo "deploy: start it with 'komizo proxy --host <this box>', or press s in the interface." >&2
1248:	echo "deploy: 'komizo start --host ...' brings up $version, or press s in the interface."
1289:	echo "deploy: 'komizo start --host ...' brings up $version, or press s in the interface."

These are printed into GitHub Actions deploy logs, so they are the most widely seen reference to the deleted interface in the repo — more so than the README this PR did fix.


Non-blocking

a. 57 functions became unreachable and the PR does not say so. deadcode ./... on this branch versus on main:

timerange.go  every function: empty, span, orDefault, parseRange, parseMoment,
              parseOffset, rangeText, stampText, durText
metrics.go    metricRow.total, series.blankOutside, series.any, seriesWhere,
              seriesFor, seriesForBox, seriesForService, servesAnyHostname,
              trailingBaseline, trailingPoisson, quietened, medianOf
system.go     boxCPUAt, containerCPUAt, appCPUAt, cpuAt, memAt, diskAt,
              cpuSeries, memSeries, diskSeries, storageSeries, mountsIn,
              volTotal, pctText, csKey, cgroupStat.key, sysSample.statFor,
              diskUse.frac, resSeries.any
report.go     metricsFromBox, metricSpanFrom, sysSampleFrom, volumesFromBox,
              samplesFrom
list.go       appRow.up/upSince/downSince/stateText,
              containerRow.up/stateText/portsList, serverRow.osName
ssh.go        target.hostDisplay, target.isIP
reach.go      reachResult.summary
output.go     since

This is what makes findings 5, 6 and 7 easy to miss on a read: the source still looks like it can answer those questions.

b. The stated reason for keeping defaultWindow is not true in this tree. The comment and the PR body both say "komizo report and every signed read still resolve one". No CLI command sends a range — grep '"--from"' across internal/app non-test code returns nothing, and orDefault has only test callers. Changing defaultWindow from 4h to 1h leaves the suite green. Either wire it up or let it go with the rest of timerange.go.

c. devLimit was moved to metrics.go for a function nothing calls. Its only use is metrics.go:360, inside trailingPoisson, which has no caller including tests. Mutating the clamp to 0 stays green. The comment's claim — "it decides a number this package computes" — is true only of a computation no user can reach.

d. since() is new dead code. Added to output.go:194-227, moved verbatim from tui_style.go:465, with a doc comment that says "the one format this page uses" — there is no page. No caller, not even a test. Mutating its whole body to return "WRONG" leaves the suite green.

e. addResult carried the interface's cursor state into add.go. cursor, onClipboard, copyErr, changedConfig, namesChanged, changedNames and the onClipboard: -1 initialiser are all write-only now; only key, knownHosts and config are read. Deleting the lot stays green. The comments still describe "the screen handing over the other two values" and "for as long as this screen is open".

f. The interactive host-key path is now dead (item on host-key handling). acceptHostKey(t, false) — the branch at reach.go:186-198 that prints fingerprints and asks y/N — had exactly one caller, tui.go:1284. The surviving ensureReachable only ever calls acceptHostKey(t, true). komizo itself never shows a fingerprint now; it tells you to run ssh HOST and look, which is a fair answer, but 20 lines of unreachable prompt remain and read as live.

g. Surviving tests of unreachable code. system_test.go's quietened/trailingBaseline cases are the largest block of tests in the package that assert on behaviour no command can produce. Not wrong to keep if the app grows into them; worth a comment saying which reader they are for, since right now they are the only thing keeping those functions alive.

h. capture does not restore the globals if f panics (item 4). Safe today — there is no t.Parallel() anywhere in the repo, and go test ./... isolates packages in processes — but there is no defer, so a panic leaves os.Stdout and os.Stderr pointing at a pipe and leaks the reader goroutine for the rest of the package. Demonstrated:

os.Stdout was NOT restored after a panic: still |1 (a closed/leaked pipe)

defer func() { os.Stdout, os.Stderr = outOrig, errOrig }() and a defer r.Close() cost nothing. Adding t.Parallel() to any test in this package later will break it silently.

i. TestRegisteringIsNotFatalToSetup stops reading at the first blank line. Making registration fatal with a blank line before the return stays green:

		note("could not register this server: %v", err)

		return err
	}

Pre-existing, not introduced here, but it is in the file this PR rewrote and the AST walker beside it could answer the question properly.

j. Typo, update.go:110-112: "komizo list and the\n the app will not work" — doubled "the".

k. AGENTS.md:1-6 still heads with "Go and Bubble Tea HAVE CHANGED" and links the Bubble Tea docs as required reading. This PR deletes that dependency from go.mod; the file telling every contributor to go read its docs should go with it.

l. Present-tense comments about the interface remain in ~20 files. The PR body accounts for lifecycle.go's as deliberate history, which I accept. But reach.go:249, report.go:60, ssh.go, output.go, system.go and add.go describe the interface's current behaviour ("the interface polls the box every five seconds", "this runs under a full-screen program"), which is a different thing from recording why something was built. Cheap to sweep in the same pass.


What would clear this

1–4 and 9 are small and concrete: a flag or two on komizo add, a string in remove.go, three strings in alpine.sh. 8 is a real fix to the guard the PR is leaning on. 5, 6 and 7 are the judgement call — either they come back as flags on report/list, or the parity rule gets rewritten in this PR to say that watching a box is the app's job and the CLI's floor is something narrower. What should not happen is the rule staying as written while three classes of information quietly stop being reachable.

Review 1 on nicodes/komizo-be#55 walked the deleted screens rather than the
diff, and found the parity sweep had missed several. Two of them were worse
than a missing read.

CHANGING A SETTING ROTATED THE DEPLOY KEY. `keepKey` survived, `performAdd`
still honoured it, the box script still documented it -- and the only
caller was the interface's `c`. So `komizo add --config NEW` issued the
repo a key it does not know about and broke its next deploy for a reason
nobody would connect to what they just did. `--keep-key` is that caller.

AND THE KNOWN-AS LIST COULD BE ADDED TO BUT NEVER CLEARED, because an
empty value means both "I did not say" and "I say: none" and nothing asked
the parser which. fs.Visit knows.

READING KOMIZO_KNOWN_HOSTS COST A KEY ROTATION -- formatKnownHosts was
reachable only through `komizo add`. It is `komizo report --known-hosts`,
which reads and writes nothing.

VOLUMES, PROCESSOR USE AND REQUEST COUNTS had no command at all. The
decoders for all three survived the deletion and became unreachable, which
is why the source still looked like it could answer. They are --volumes
and --usage on `komizo report`, behind flags because each costs something
the plain report does not.

AND THE GUARD ITSELF COULD BE WALKED PAST TWO WAYS, both the original
bug's shape. It matched the script by NAME, so a package-level alias hid a
setup path entirely; and it exempted any selector beginning with "Print",
so a runner called PrintAndRun was treated as `komizo script init` -- while
rewriting fmt.Print as fmt.Fprint went red for no behavioural change. It
now follows the VALUE through its aliases, and asks who the receiver is.

    caught  --volumes never reaches the box
    caught  the volumes are fetched and not printed
    caught  a shared volume is counted once per mounter
    caught  --usage never calls the box
    caught  the processor figure is dropped
    caught  --known-hosts prints nothing
    caught  known_hosts drops the app's own names
    caught  a setup path whose script reference is a package-level var
    caught  a setup path whose runner method is named Print*

askBox and ensureReachable become package variables so those assertions run
against the real command rather than the decoders -- a capability added
without a way to assert it is the next one to go missing quietly.

Also: `komizo remove` no longer sends people to the invocation this branch
deleted, alpine.sh stops telling deploy logs to press a key in a program
that is gone, AGENTS.md stops requiring Bubble Tea's docs, and capture()
restores the globals on a panic.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@nicodes

nicodes commented Aug 8, 2026

Copy link
Copy Markdown
Owner Author

Review 1 reply

All nine blocking fixed. This is the best review I have had on this branch, and finding 2 in particular is one I would not have found by reading the diff — you found it by walking the deleted screens, which is the only method that could have.

2 — a settings change rotated the deploy key

Confirmed and fixed. This is the one that would have hurt somebody: komizo add --config NEW on a live app issued that repo a key it does not know about, and the next deploy fails with nothing connecting the failure to the change. --keep-key is the missing caller.

The shape is worth naming, because it is not "a screen was deleted": the capability, the plan field, the script support and the comment explaining it all survived. Only the caller went. Nothing in the type system or the tests notices a struct field with no producer.

3 — --known-as "" could not clear

Fixed with fs.Visit. An empty string means "I did not say" and "I say: none", and only the parser knows which. The interface's prompt said it out loud — "Comma-separated, and empty is an answer" — and the flag had no way to.

4 — reading KOMIZO_KNOWN_HOSTS cost a key rotation

komizo report --known-hosts, which reads and writes nothing. Per app and scoped to that app's names, because known_hosts matches the exact string the client dialled.

5, 6, 7 — volumes, processor, request counts

Not a judgement call, and I should not have treated the parity rule as the thing to reinterpret. The standing rule here is that the CLI may never say less than the app. All three are in the app, so all three come back:

  • komizo report --volumes — per-app sizes, shared volumes counted once
  • komizo report --usage — processor over the last two readings, and requests/5xx per app

Behind flags because each costs something the plain report does not: --volumes walks every volume, --usage is a second call. --usage is also what makes defaultWindow load-bearing again, which answers your non-blocking (b) — you were right that its stated reason was false in that tree.

8 — the guard could be walked two ways

Both closed, and both were the original bug's shape. It matched by NAME, so var provisionScript = scripts.AlpineInitScript hid a path entirely; and isPrintArg accepted any selector beginning with "Print". It now follows the value through its aliases and asks who the receiver is:

caught  a setup path whose script reference is a package-level var
caught  a setup path whose runner method is named Print*
ok      fmt.Print rewritten as fmt.Fprint (no longer a false red)

Your Fprint point was the one that told me the rule was wrong rather than merely narrow — a guard that breaks on a no-op refactor is measuring the wrong thing.

1 and 9 — strings

Fixed. Point taken that the alpine.sh ones are the most widely seen reference to the interface in the repo, more than the README.

The new capabilities are asserted, not just added

askBox and ensureReachable are package variables now so the assertions run through the real command. That is deliberate rather than convenient: a capability added without a way to assert it is the next one to go missing quietly, which is precisely what this review is about.

caught  --volumes never reaches the box
caught  the volumes are fetched and not printed
caught  a shared volume is counted once per mounter
caught  --usage never calls the box
caught  the processor figure is dropped
caught  --known-hosts prints nothing
caught  known_hosts drops the app's own names

Non-blocking

Taken: (b) defaultWindow is live again, (h) capture restores on panic with a defer, (j) the doubled "the", (k) AGENTS.md no longer requires Bubble Tea's docs.

Not taken in this PR, deliberately: (a) the dead code. --usage and --volumes revived nine of those functions, and deadcode still lists about forty — all of timerange.go's parsing, the anomaly scoring, most of the series machinery. Deleting them is right and it is another two thousand lines on a branch already at twelve thousand. Filed as its own issue rather than folded in; (c), (d), (e), (f), (g) all belong to it and are named on it.

Also: you are right that docs/checks.md does not exist in this repo. It is in komizo-be. I have been citing it in review briefs as though it were here. Filed.

@nicodes
nicodes merged commit 3d71ef6 into main Aug 8, 2026
2 checks passed
nicodes added a commit that referenced this pull request Aug 8, 2026
…ent (#94)

Hit on a real box. `go run github.com/nicodes/komizo@v0.0.17 init` set up
Docker, the shared network and the metadata block, then failed at the agent
with "this komizo was built without a linux/amd64 agent" -- leaving a
server provisioned and unreadable.

Not a broken release. The agents are gitignored build artifacts: `make
agents` builds them and the release workflow runs it, but the module the Go
proxy serves carries bin/.keep and nothing else. So the module form of `go
install` and `go run` compiles happily and fails at the one step that puts
the agent on the box -- after everything else has already been done to it.

The README recommended exactly that as its FIRST command. It leads with the
release archive now, and says plainly why the Go path does not work and
what does (a checkout, where the Makefile builds the agents first).

The error message said "Built from source? Run `make agents`" -- advice a
`go install` user cannot take, because they have no checkout. It names that
case and points at the releases page.

AND A CHECK, because the sentence is easy to reintroduce and nothing else
here would notice a documentation defect with a half-provisioned machine at
the end of it. The rule is not "never mention go install": from a checkout
it is fine. It is that the module form must never appear without the reason
it does not work beside it.

Also: init.go still said the "monitor" would not work -- the monitor was the
interface, deleted in #86. I fixed that wording in update.go and missed the
copy here, which is the same instance-not-shape mistake as the CI ceiling.
Swept the repository for the class this time; this was the only remaining
user-facing one (the komizo_monitor hits are the service account).

    caught  the README stops saying the module install does not work
    caught  the README stops naming make agents
    caught  the README stops showing the working install
    caught  the error stops naming the go install case

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant