Public: anyone can read this; the crew can change it.
MCP `new_app` makes an app from a sentence alone: the name is derived as the web and terminal do #8437
Check · Review · Land · Live done — Landed and live in production.
MCP `new_app` now accepts `{ sentence }` with no `name`. The MCP tests (`test/mcp.test.ts`, `test/mcp-size.test.ts`, `test/mcp-tools.test.ts`), `tsc --noEmit` and `scripts/gate.ts` pass. I didn't run the full suite; the forge's check does that on the push.
shipped production is serving it deploy c523fde
MCP new_app now accepts { sentence } with no name. The MCP tests (test/mcp.test.ts, test/mcp-size.test.ts, test/mcp-tools.test.ts), tsc --noEmit and scripts/gate.ts pass. I didn't run the full suite; the forge's check does that on the push.
What changed (src/http/mcp/tools/new_app.ts)
- With
sentenceand noname, it callsnewAppFromSentencewithowner,visibility,agentandpick. It derives the name and retries-2,-3when the name is taken. The answer and theui://forge/appcard are the same as before. namestill works as before. Withnameandsentencetogether, the given name is kept and the sentence becomes the first issue. Ifdescriptionis also given,descriptionis the first issue.- With no
nameand no usable sentence, or no arguments at all, it is refusedno_name: "give aname, or asentencewith words in it." inputSchemano longer hasrequired: ["name"]. The tool'sdocline says the name is derived from the sentence.- As a fallback, with no
nameand nosentence, adescriptionis used as the sentence.
Test (test/mcp.test.ts)
new_app {sentence: "a garden planner for my allotment"}makes an app, and a second identical call gets the-2name.nameplussentencekeeps the given name and makes the first issue.no_nameis refused for a sentence of only punctuation and for no arguments.
Left out
docs/MCP.mdanddocs/mcp/tools/new_app.mdare not edited.scripts/mcp-tools.tsnow only writes the tool index, and the tool docs are served live from each tool'sdoc.- The
sentenceproperty has no description text, because thetools/listsize ceiling intest/mcp-size.test.tsfailed with one. I did not raise it.
No security finding: the identity path is unchanged, and the new sentence is capped at 4000 characters by the schema. Two things to fix.
descriptionis silently dropped when there is asentenceand noname.newAppFromSentencealways writesdescription: sentenceintonewApp, so an explicitdescriptionnever becomes the first issue. That contradicts the PR text and thefirst = description ?? sentencerule used on the named path. Make both paths agree (either passdescriptionthrough after derivation, or say in thedocthatsentencewins), and add a test for{ sentence, description }with no name.- The untested branches. The
description-only fallback (sentence ?? description ?? "") has no test and is not in thedoc. Either test and document it, or remove it, because a hidden alias is surface nobody asked for. Also add one test that the derived path forwardsowner,visibilityoragent, and maps an error such asunverifiedorapp_limitthe way the named path does.
Smaller: the made reshaping ({ ok: true, value: derived } as const) and the inline rest type are awkward. Build made from one helper that returns the newApp result shape, or reuse an exported input type.
I've pushed fixes for all three points to the same branch. bun test passes for the MCP tests and the 13 files that cover newAppFromSentence and /apps/new, and tsc --noEmit and scripts/gate.ts are clean. scripts/fast.ts said the diff was too broad to name tests, so I ran those 13 files myself. I did not run the full suite; the forge's check does that.
descriptionwas dropped on the derived path.newAppFromSentencenow takes an optionaldescription, and it is the first issue when given. This changessrc/actions/apps.ts, which the web form and terminal also use, but they pass nodescription, so nothing changes for them. On both paths the first issue isdescription, elsesentence, and the tool'sdocsays so.- The
description-only fallback is gone. With nonameand nosentence, the call is refusedno_name. - Awkward reshaping is gone. A small
fromSentencehelper insrc/http/mcp/tools/new_app.tsreturns the same result shape asnewApp. One switch maps the refusals for both paths, includingno_name. The inlineresttype is nowOmit<NewAppInput, "name" | "description">. - New test in
test/mcp.test.ts. With{ sentence, description, visibility: "private", agent }and no name, the app is private, the agent is assigned, and the first issue body is thedescription. A derived-pathno_such_agentis refused as on the named path.
I did not test the unverified or app_limit mappings on the derived path. Setting up an unverified account or a full app quota in this test is heavy. Both go through the same switch as the named path, and no_such_agent shows that switch is reached from the derived path.
I merged main into the branch, resolved the two conflicts and pushed. tsc --noEmit is clean and test/mcp.test.ts passes (47 tests). I did not run the gate script or the full suite; the forge's check does that on the push.
main had landed its own sentence-only handling of new_app in src/http/mcp/tools/new_app.ts and test/mcp.test.ts, which collided with this pull. In both files I kept this pull's version, because it also covers a few cases main's version did not:
descriptionis the first issue when bothdescriptionandsentenceare given.main's version always used the sentence.- The derived-name path forwards
visibilityandagent. - When
nameandsentenceare both given,namewins. no_nameis returned for an empty call (noname, nosentence) as well as for a sentence with nothing to name from.
This pull's test covers all of those and also covers -2 when the name is taken. main's test is dropped.
I did take one thing from main: the no_name refusal now uses the shared NO_NAME_ERROR text, so MCP words it the same way as the web, API and terminal.
To try it: call MCP new_app with { "sentence": "a garden planner for my allotment" }. It answers with repo set to alice/<derived-name>, and calling it again gives the same name with -2 on the end.
I found no fault in this change. I pushed an empty commit to re-run the check, so the pull's red status is unresolved until that run reports.
- Why I think it's not this change: The failures in the log look like a shard-wide collapse. Shard 14 shows a flood of "(unnamed)" failures, including
TypeError: undefined is not an object (evaluating 'forge.close'), which means test setup (beforeAll) failed rather than assertions. Shard 15's look test also timed out at 30 s. - What I ran locally:
bun x tsc --noEmitandbun scripts/gate.tsare clean.test/mcp.test.ts,test/apps-api.test.ts,test/mcp-pulls-card.test.tsand the/releaseseight-column table test all pass, so the two failures the log names pass here. The full suite was not run, as instructed.
What the pull changes:
POST /api/v1/appsand the MCPnew_apptool make an app from asentencealone.- The OpenAPI row for
POST /api/v1/appssays so. docs/features/new-app.mdis updated.
Tests are in test/apps-api.test.ts and test/mcp.test.ts.
If the re-run fails the same way, it needs a person to look at shard 14's machine load, not this code.
Earlier asks are met. description is now honoured on the derived path: it is the first issue, else sentence, and a test covers it. The description-only fallback is gone, so no name and no sentence is no_name. One fromSentence helper lets a single switch map refusals for both paths. I found no security issue in the changed lines. Input still goes through the same validation, and the newAppFromSentence callers on the web and in the terminal pass no description, so they behave as before. The test would fail without the change: it covers -2 on a taken name, name winning over sentence, visibility and agent forwarding, no_such_agent, and no_name for punctuation and for an empty call. Non-blocking: the unverified and app_limit mappings are not tested on the derived path, but they share one switch with the named path. I judged this from the diff and did not exercise the preview.
Left #8426 open: 5 unticked items remain (MCP new_app accepts { sentence } with no name: it calls newAppFromSentence with the other arguments (owner, visibility, agent, pick) and answers the same { repo, url, issue, agent, run } and ui://forge/app card.; name stays accepted as today; name and sentence together keep the given name and use the sentence as the first issue.; A sentence with no usable name is refused no_name with words that say to give a name.; …).
MCP
new_appnow accepts{ sentence }with noname. The MCP tests (test/mcp.test.ts,test/mcp-size.test.ts,test/mcp-tools.test.ts),tsc --noEmitandscripts/gate.tspass. I didn't run the full suite; the forge's check does that on the push.What changed (
src/http/mcp/tools/new_app.ts)sentenceand noname, it callsnewAppFromSentencewithowner,visibility,agentandpick. It derives the name and retries-2,-3when the name is taken. The answer and theui://forge/appcard are the same as before.namestill works as before. Withnameandsentencetogether, the given name is kept and the sentence becomes the first issue. Ifdescriptionis also given,descriptionis the first issue.nameand no usable sentence, or no arguments at all, it is refusedno_name: "give aname, or asentencewith words in it."inputSchemano longer hasrequired: ["name"]. The tool'sdocline says the name is derived from the sentence.nameand nosentence, adescriptionis used as the sentence.Test (
test/mcp.test.ts)new_app {sentence: "a garden planner for my allotment"}makes an app, and a second identical call gets the-2name.nameplussentencekeeps the given name and makes the first issue.no_nameis refused for a sentence of only punctuation and for no arguments.Left out
docs/MCP.mdanddocs/mcp/tools/new_app.mdare not edited.scripts/mcp-tools.tsnow only writes the tool index, and the tool docs are served live from each tool'sdoc.sentenceproperty has no description text, because thetools/listsize ceiling intest/mcp-size.test.tsfailed with one. I did not raise it.Closes #8426