Land the rest of the agent-first stack on main - #15
Merged
Merged
Conversation
The toolchain shipped before the document that explains it. An agent handed someone's house could read the SDK reference and the template, but nothing stated the judgment neither of them carries: that the coordinator is the only place authorization happens, that component requirements and coordinator grants intersect silently so a mismatch renders a hole instead of raising, and that a call whose outcome is unknown must never be retried because the lamp may already have moved. Everything here is taken from the code it describes: the UI vocabulary and limits from packages/component, the command surface and the exit-code table from packages/cli, the ordering and authorization rules from templates/home. The two CI lessons are the ones this repository paid for on #10 — a check that exists is not a check that runs, and a local run under the wrong Bun proves nothing about the runner. Closes the second deliverable of workstream F.
The guide tells an agent to characterize an existing installation before writing anything, and then leaves it to do that by hand. Most houses arriving at V4 already run Node-RED with the v3 MiakAPI nodes, and their flows export already answers most of the questions: which brokers exist, which topics the devices actually use, which variables were committed, which actions users could invoke and who was allowed to invoke them. `miakapp discover --flows <path>` reads that export offline and turns it into an inventory. It needs no project file and no Home Key, because the house it reads has no V4 project yet. Three things it will not do. It never opens a socket or writes back into the export. It never drops a node silently: every type it does not model is counted and reported, so the reader knows what the inventory missed. And it never guesses which actions are physically consequential -- it lists them all and leaves that judgement to the reader. Four findings decide work that is otherwise discovered late: - the v3 initMiakapi node declares coordSecret in its defaults rather than its credentials, so Node-RED stores that secret in cleartext in flows.json instead of the encrypted flows_cred.json. If it is there, it is leaked. - the v3 handler allows an action outright when its node lists no group, so an empty allowedGroups is a grant to every signed-in user, not a deny. - a v3 name that V4 would reject has to be renamed while nobody depends on it. - a topic holding # or + is a subscription pattern, not one device. Field names come from the two real schemas: Node-RED core mqtt in, mqtt out and mqtt-broker, and the node-red-contrib-MiakAPI v3 node definitions. No real export was available to test against, so the parser recognizes nodes by type and reads only fields it knows.
An agent that speaks MCP natively had to spawn a shell, quote arguments and parse output to publish a component. `miakapp mcp` serves the same commands as tools over newline-delimited JSON-RPC on stdio. The server is a translation layer and nothing else: a tool call becomes the exact argv a person would have typed, then runs the same dispatch. There is no second implementation of an option, a default or a validation rule, and a test proves the tool surface exposes every CLI option and invents none. Two deliberate departures from the command line: - publish, activate and rollback refuse to run without `confirm: true`. The guard is checked before anything else and never reaches the argv, so a model that hallucinated a publication spends the mistake on an argument check rather than on a generation; - a command failure comes back as a tool result carrying `isError`, not as a JSON-RPC error. A protocol error means the call never happened; a publication that reached the control plane and failed did happen, and only `kind` tells the caller whether to reconcile. Nothing but framed JSON-RPC reaches stdout: the dispatch runs against a host that captures its own rendering, because one stray line would desynchronize the stream for the rest of the session. Zero new dependencies. 37 tests, including a live handshake shape, a message split across chunks, and a guarded publish proving the control plane was never contacted.
The toolchain, the guide and the contract all existed, and none of them were where a coding agent actually looks. An agent opening the owner's home repository reads AGENTS.md or CLAUDE.md, and finds whatever the owner wrote there — which is not this. `miakapp agent-pack` puts the knowledge in the repository: the guide as a file under .miakapp/, a pointer to it in both instruction files, and the MCP server registered in .mcp.json so the tools are wired rather than described. The CLI's rule that it never rewrites what it did not generate is what shapes every merge. The guide is a file the command owns outright. The instruction files are edited only between markers it wrote, so prose above and below survives byte for byte and a second run rewrites the block in place instead of stacking another copy. .mcp.json is merged as a structure, one key by name: every other server survives, and a file that does not parse is refused rather than replaced with a valid one. Two new FileSystem methods carry this — `replace` is deliberately separate from `write`, so overwriting stays something a command asks for rather than something it falls into. The guide ships as a package asset, and a test asserts it is byte-equal to docs/agent-guide.md. Editing the doc without copying it across is a red test, not a pack that teaches an agent rules the CLI no longer has. Verified against the built binary, not only through injected tests: the pack installed into a repository with its own AGENTS.md and its own .mcp.json kept both, `claude mcp get miakapp` reads the generated entry back as a project-scope stdio server, a second run reported every file unchanged, and miakapp_agent_pack installed a pack over real MCP stdio.
Put the guide where the agent actually looks: miakapp agent-pack
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#10 landed on
main. #11, #12, #13 and #14 were merged while GitHub had not yetretargeted them off the stack, so each landed in its own base branch instead of
main: the guide intomathieu/agent-cli,discoverintomathieu/agent-guide,the MCP server into
mathieu/agent-discover, andagent-packintomathieu/agent-mcp. No content was lost —mathieu/agent-mcpnow holds all four.This carries them to
mainin one commit. The diff is exactly the union of thefour already-reviewed pull requests:
docs/agent-guide.md— the guide an agent reads before building a homemiakapp discover— read an existing Node-RED house before designing onemiakapp mcp— the CLI as MCP tools, withconfirm: trueon physical actsmiakapp agent-pack— put the guide where the agent actually looksVerified on the union with the pinned toolchain (bun 1.2.23), from a clean
bun install --frozen-lockfile:bun run checkexit 0,bun run check:packagesexit 0 — cli, component, template and the publishable artifact all green.