Skip to content

feat(cli): explain how to connect an agent from the CLI and console - #174

Merged
oesni merged 5 commits into
mainfrom
feat/cli-agent-connect-help
Oct 24, 2026
Merged

oesni merged 5 commits into
mainfrom
feat/cli-agent-connect-help

Conversation

@rabbitson87

@rabbitson87 rabbitson87 commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Summary

A user with a running host could not tell how to connect an agent from the CLI. flats connect sounds like the answer but only chooses the host. flats help <command> printed a single usage line. The console's Settings > Agents page lacked the plugin, the Codex approval caveat that flats mcp-config prints, and any way to check the connection.

This change adds that guidance. It changes text and layout only.

Changes

CLI

  • Bare flats connect says it only chooses the host and points to flats mcp-config. It prints this for every host source (saved, FLATS_URL, --url, default) and not for --json, --clear or a save.
  • flats help ends with a pointer to flats status and flats mcp-config. The connect, mcp and mcp-config synopses say what the commands do.
  • flats help <command> and <command> -h print the usage line first (unchanged), then the synopsis and, for connect, mcp, mcp-config and client, a description. -h then lists the flags.
  • --url is named URL in -h output. It printed -url flats connect because the usage text contained a backticked phrase, which Go's flag package uses as the argument name.
  • flats mcp-config text names the plugin install commands for Claude Code and Codex and points to docs/agents.md#plugin for Cursor. Its description says --json has the registration commands without the plugin commands, because that is what the JSON holds.

Console, Settings > Agents

  • Each client tab shows two blocks, the plugin and the direct MCP registration, with a Copy button each. The two are alternatives, so one paste never does both. Each block is named by its title for screen readers.
  • The Codex tab carries default_tools_approval_mode = "approve" and the trusted-agents caveat that flats mcp-config prints.
  • Unless the console is opened on http://127.0.0.1:7878, the plugin and CLI blocks start with flats connect <origin>. The plugin and the CLI use the host saved on their own machine, or http://127.0.0.1:7878 when none is saved, so any other address (another device, or a loopback console on another port) has to be saved first. The CLI tab's note names that default.
  • The copied blocks paste cleanly into interactive zsh: no block holds an apostrophe, and the shell blocks (plugin and CLI) hold no # line. The Cursor plugin block's follow-up step ("Then install Flats from the Cursor plugin list") is in the block title, which is not copied. The Codex TOML block is a config file and keeps its comments.
  • A "Check the connection" row says to restart the agent and list its tools, that the first call is check_client, and that flats status and flats mcp-config work from a terminal.
  • At phone width the code blocks wrap inside their card. Before this change a block was as wide as its longest line (452 px against a 386 px card at a 420 px window), so it ran past the card and could not be read or scrolled. The longer plugin line made that worse (561 px).

Docs

  • README "Agent integration", docs/agents.md and docs/surfaces.md. The README paragraph about get_runtime_reference is unchanged, as TestRuntimeDocsDiscoveryConsistency requires.

Later commits

The review record below covers the first commit, 4edceaf. Three commits came after it:

  • 5dcc865 (fix(console): keep the Cursor plugin snippet free of shell quotes #177, merged into this branch): the zsh paste fix above. The Cursor plugin block had a # ... line with an apostrophe, so a pasted block stopped at quote> or printed command not found: #. ui_test.mjs asserts that no copied block holds an apostrophe and no shell block holds a # line.
  • fb21947: the first commit left out flats connect <origin> on any loopback address. A console on another loopback port (a custom management port, or a Compose port mapping) then showed plugin and CLI blocks that talk to http://127.0.0.1:7878, a different host. Now the line is left out only on http://127.0.0.1:7878. ui_test.mjs covers http://127.0.0.1:17878 and http://localhost:7878, and TestAgentsDefaultOriginMatchesCLI keeps the page's default equal to the CLI's DefaultURL. Restoring a loopback-only check fails the new assertion. An independent review of this commit approved it with no findings. go vet and go test -count=1 ./internal/console ./internal/cli pass.
  • 035e4ac: TestMCPConfigNamesPluginInstall decodes mcp-config --json and compares its keys at each level with what mcpConfig writes, instead of only checking that the word plugin is absent. Adding a field fails it.

Not changed

--json output of every command, exit codes, flag names, MCP tools and instructions, flats status output, and the plugin skill (so no bootstrap revision change).

Compatibility

Bare flats connect gains a last line. Its first line is unchanged. No script in the repository parses it.

Verification

  • gofmt -l . is empty and go vet ./... exits 0.
  • go test ./... -count=1 passes in every package, including the node console UI test.
  • make docs-verify and make docs-audit exit 0. The audit warns only about files this change does not touch.
  • New tests: internal/cli/help_test.go, additions to internal/cli/connect_test.go and the Agents section of internal/console/testdata/ui_test.mjs, including a non-loopback case that restores location.
  • Mutation checks: 11 mutations of the product code (drop the hint, restore the backticks, share one block name, print the hint for one host source only, and others), each caught by a test in the final run. Three survived at first (one found by the author, two by the reviewer) and led to stronger assertions. The reviewer's other surviving mutations are listed under Limitations.
  • Real browser, against a disposable host with synthetic data, at 1280 px and 420 px on every tab: block count, names, Copy labels, no overflow and no scrollbar. Real clicks on both Copy buttons of the Codex tab copied only their own block. ArrowRight, Home and End moved focus and selection, with wrap-around.
  • The built binary was run against that host for every changed CLI path.

Review record

Authors of all code, tests and docs: claude-sonnet-5-5. Every review ran in a fresh session on a read-only copy of the exact snapshot, with the model claude-fable-5-1. The effective model came from execution metadata (claude -p --output-format json, modelUsage), not from the model's own answer. The reviewer is the same vendor as the author. No reviewer from another family was available on the machine.

Review Verdict line Disposition
Design, revision 1 VERDICT: APPROVE 8 suggestions, all accepted
Design, revision 2 VERDICT: APPROVE 5 low findings, all accepted
Implementation, candidate 1 VERDICT: REJECT 1 blocker: flats help mcp-config said --json prints "the same commands", but the JSON has no plugin commands. Fixed. Also 6 suggestions, all accepted. One of them was a real bug: a single Copy button copied two alternatives
Implementation, candidate 2 VERDICT: APPROVE 3 suggestions. Two accepted, one kept (the console file already uses curly apostrophes)
Carry-forward and testing IMPLEMENTATION CARRY-FORWARD: ACCEPT and TESTING VERDICT: APPROVE 5 suggestions. Accepted: the -h exception list, the weak block-name assertion, the one-source hint test and the report overstatement. The fifth covered three smaller surviving mutations, which are listed under Limitations
Delta IMPLEMENTATION CARRY-FORWARD: ACCEPT and TESTING VERDICT: APPROVE Two cosmetic notes: two failure messages (fixed) and a docs clause slightly weaker than the binary (left as it is, not false)
Carry-forward of that fix IMPLEMENTATION CARRY-FORWARD: ACCEPT and TESTING VERDICT: APPROVE None

The design record, the verification report and the full reviewer reports are in a local-only task report on the author's machine, so a remote reader cannot open them. The verdict lines above are quoted exactly. The review budget was raised from 6 to 7 invocations, with the reason recorded, for the last carry-forward.

Limitations and follow-up

  • The branches that add flats connect <origin> (another device, another loopback port or name) are covered by the unit test only. The browser reached the host on loopback.
  • Not checked: the light theme in a browser, real Tab-key traversal (the embedded browser's synthetic key events did not move focus), other browser engines and Linux or Windows. The new CSS sets no colors.
  • Manual or browser evidence only, with no automated assertion (surviving mutations the reviewer reported): the wording of the mcp and mcp-config synopses, the Copy button aria-label text, that the direct blocks omit flats connect <origin>, and that the Codex approval line sits only in the direct block.
  • flats help <command> prints the synopsis for every command, but only four have a longer description. The other commands can get one later.
  • Screenshots of every tab at both widths exist on the author's machine with synthetic data. They are not attached because the CLI cannot upload PR attachments.

For the maintainer

Main moved after this branch was cut, from a831c45 to 1ce795d (#173, #176, #178, #179, #180, #181). b3e3018 merges that main into this branch without conflicts; README.md, docs/surfaces.md, app.css and ui_test.mjs had changed on both sides. Before the push, go build ./..., the cli, console, docs and plugins tests, the docs-budget shard and make docs-check passed on the merged tree.

test (docs) timed out on earlier heads in TestGuestBusyResendKeepsOrder, a test from #180 that also failed on main. #181 fixed it, and every required check passes on b3e3018.

The #177 commit carries a Co-authored-by: gormes-agent[bot] trailer, which a squash merge would likely carry onto main.

Check that the required checks ran on the current head before merging.

A user with a running host could not tell how to connect an agent. `flats
connect` sounds like the answer but only chooses the host, `flats help
<command>` printed one line, and Settings > Agents lacked the plugin, the
Codex approval caveat and any way to check the connection.

CLI:
- Bare `flats connect` says it only chooses the host and points to
  `flats mcp-config`.
- `flats help` ends with a pointer to `status` and `mcp-config`; the
  `connect`, `mcp` and `mcp-config` synopses say what they do.
- `flats help <command>` and `<command> -h` print the usage line, the
  synopsis and, for connect, mcp, mcp-config and client, a description.
- `--url` is named URL in `-h` output instead of `flats connect`.
- `flats mcp-config` text names the plugin install commands.

Console, Settings > Agents:
- Each client tab shows the plugin and the direct MCP registration as two
  blocks with a Copy button each, so one paste never does both.
- The Codex tab carries the approval line and the trusted-agents caveat
  that `flats mcp-config` prints.
- Off-loopback consoles start the plugin and CLI blocks with
  `flats connect <origin>`.
- A "Check the connection" row says how to tell that the agent is connected.
- At phone width the code blocks wrap inside their card instead of running
  past its edge.

Docs: README "Agent integration", docs/agents.md and docs/surfaces.md.

`--json` output, exit codes, MCP tools and `flats status` are unchanged.
Comment thread internal/console/static/assets/js/settings.js Outdated
@gormes-agent

gormes-agent Bot commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Review of 4edceaf (base 9c68085, merge base a831c45)

Verdict: approve after one small fix (comment only, not a formal review). The change keeps to text, layout and help output as described. --json output, exit codes and flag names do not change. I found one defect in a copied snippet.

Should fix

  • internal/console/static/assets/js/settings.js:1732: the Cursor plugin block's Copy button copies # then install Flats from Cursor's plugin list. In interactive zsh (the macOS default; interactive_comments is off), the apostrophe opens an unterminated quote, and the paste hangs at quote>. Reproduced with zsh -fi. See the inline comment.

Non-blocking notes

  • help_test.go:84: the check for unchanged mcp-config --json output only asserts that the word plugin is absent. It does not pin the JSON shape. Decoding it and comparing its keys with the base would back up the "JSON output keeps its shape" claim.
  • Text output of bare flats connect gains a final line. The PR states this and nothing in the repository parses it. External scripts that use tail -1 would see the change.
  • ops.go:425: the claim that the plugin needs the CLI on the agent's PATH is repeated in the CLI, the console title, the README and docs/agents.md. That is fine for now, but these copies will need updating together.

Verified OK

  • reportConnection: the hint appears only on bare connect (note == "") and never with --json, on save or with --clear. This matches the description.
  • -url URL: the backticks in the flag usage now name the argument correctly.
  • consoleOnServer() already exists in ui.js, and the non-loopback branch prepends flats connect <origin> to the plugin and CLI blocks only.
  • h() drops null attributes, so untitled blocks get no dangling aria-labelledby.
  • No merge conflicts against current main (git merge-tree).

Verification

  • Local: gofmt -l internal/ printed nothing. go vet ./internal/cli ./internal/console passed. go test ./internal/console passed, including the node UI test. In ./internal/cli, every test except two passed. TestBoardCommands and TestAgainstRealAPI fail with *.localhost DNS errors in my sandbox. They fail the same way at the merge base, so the PR did not cause them.
  • CI: 20 check-runs at 4edceaf succeeded and commit-images was skipped. I read the check-run results but did not open the logs.
  • Not done: real browser rendering and layout, and Windows shells.

@oesni

oesni commented Oct 23, 2026

Copy link
Copy Markdown
Collaborator

@gormes-agent make pr for suggested small change

@gormes-agent

gormes-agent Bot commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

@oesni I opened #177 with the small fix from my review. It targets this PR's branch (feat/cli-agent-connect-help), so merging it adds the fix to #174.

  • The Cursor plugin snippet now reads # then install Flats from the Cursor plugin list. The apostrophe is gone, so pasting the block into interactive zsh no longer leaves it at quote>.
  • A new UI test assertion checks that no Agents tab snippet contains an apostrophe. With the old line put back, that assertion fails.
  • go test ./internal/console/ passes. I didn't test it in a real browser or a real zsh paste.

I haven't merged it.

* fix(console): keep the Cursor plugin snippet free of shell quotes

Interactive zsh does not treat # as a comment by default, so the
apostrophe in "Cursor's plugin list" opened a quote and a pasted
Cursor plugin block stopped at quote>. Reword the line and assert that
no Agents snippet contains an apostrophe.

* fix(console): drop the # line from the Cursor plugin snippet

Interactive zsh does not treat a pasted # line as a comment, so the
copied Cursor block printed "zsh: command not found: #". Move "Then
install Flats from the Cursor plugin list" into the block title, which
is not copied, and test that no shell block (plugin or CLI) holds a #
line and no copied block holds an apostrophe. The Codex TOML block is a
config file and keeps its comments.

---------

Co-authored-by: gormes-agent[bot] <343359623+gormes-agent[bot]@users.noreply.github.com>
@oesni

oesni commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator

Review of head 5dcc865 (base a831c45, including the #177 commit).

The direction is right and the change is text and layout only. One real issue, plus a couple of notes.

P2: plugin and CLI blocks point at the wrong host on a non-default loopback port

internal/console/static/assets/js/settings.js (agentsPage): chooseHost is empty whenever consoleOnServer() is true, which is any loopback host. But with nothing saved, the plugin's flats mcp and the CLI use DefaultURL (http://127.0.0.1:7878, see defaultURL() in internal/cli/connect.go). A console opened at http://127.0.0.1:17878/settings/agents (or a Compose setup publishing another host port) therefore shows plugin and CLI blocks that talk to 7878, a different or missing host. docs/agents.md already documents custom management ports (flats mcp-config --url http://127.0.0.1:17878).

The direct-registration blocks are fine because they use location.origin. The CLI tab note ("which is the host on this machine by default") is wrong in the same case.

Suggested fix: omit flats connect <origin> only when the origin is loopback and its port is 7878 (the CLI default), and add that case to ui_test.mjs.

Low: PR description is out of date

The description says the reviewed tree is the pushed tree, but #177 was merged into this branch afterwards, and the review record table does not cover it. The #177 commit also carries a Co-authored-by: gormes-agent[bot] trailer, so a squash merge will likely add a co-author line on main.

Notes (non-blocking)

  • The Codex block in the console now copies default_tools_approval_mode = "approve". It matches flats mcp-config and carries the warning, so it is consistent, but anyone pasting it turns on auto-approval of all tools even for interactive use where prompting would work.
  • The usage line says [--url url] while -h shows -url URL. Cosmetic.

Checked

  • The bare connect hint appears only in the bare text form (not on save, --clear or --json), and the tests cover this.
  • The backticked `URL` fixes the -h argument name; confirmed in the built binary's output.
  • codex plugin add / claude plugin install match the current CLIs; the docs/agents.md#plugin anchor exists.
  • Dropping the // comment line from the Cursor JSON block also fixes a block that was not valid JSON when copied.
  • go vet and go test -count=1 ./internal/cli ./internal/console pass on the head. A local merge with current main (44dfd74) is clean despite 4 overlapping files, and go build ./..., the cli/console/docs/plugins tests and make docs-check pass on it.
  • The P2 finding comes from reading the code; I did not reproduce it in a browser.

oesni added 2 commits October 25, 2026 00:10
The plugin and the CLI use the host saved with `flats connect`, or
http://127.0.0.1:7878 when none is saved. The Agents page left out
`flats connect <origin>` on any loopback address, so a console on
another loopback port showed plugin and CLI blocks that talk to a
different host. Leave it out only on http://127.0.0.1:7878, name that
default in the CLI note, and test that the page keeps it equal to the
CLI's DefaultURL.
The check that the JSON output keeps its shape only looked for the word
plugin. Decode the output and compare its keys at each level with what
mcpConfig writes, so an added or removed field fails the test.
@oesni
oesni merged commit 4b980cd into main Oct 24, 2026
21 checks passed
@oesni
oesni deleted the feat/cli-agent-connect-help branch October 24, 2026 16:41
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.

2 participants