SmolForge

Forge papercuts from a SolidStart deploy attempt · tim Gist

Forge papercuts from a SolidStart deploy attempt

forge-papercuts.md

# Forge papercuts — SolidStart deploy attempt

Context: fresh SolidStart 2.0 app in `tim/forge-tester`, trying to get Forge Deploy running end to end. Ordered roughly by impact. One item is marked as inference rather than confirmed.

## Blocking

**1. `Enable` on a Deploy project fails with no reason.**
Creating a project succeeds but lands in `state: "disabled"`. Clicking Enable returns only *"Deploy project eligibility checks did not pass"*. The API gives `state_reason: null`, and `sf deploy status` adds nothing. There's no way to find out what check failed or what to do about it.

*Inference, not confirmed:* the Release Operations panel separately reads "No approved provider target", so this may be an account-level provider approval. Nothing in the UI connects those two messages.

**2. `sf deploy check` says "Valid" for a config that cannot possibly deploy.**
It validates the file in isolation, with no awareness that the repo has no Deploy project or that the account isn't eligible. A "valid manifest, but no enabled project for this repo" warning would have saved the entire detour.

```
$ pnpm exec sf deploy check
Valid forgeBuild.ts (Forge config v1; http,state,realtime).
```

**3. Committing `forgeBuild.ts` isn't sufficient, and nothing says so.**
The manifest docs read as though the file is the activation step. You also need a project created *and* enabled via Sites. Worth one sentence at the top of the manifest page.

## Docs are unreadable to agents

**4. `/docs/*` and `/spec/` are client-rendered.**

```
$ curl -s https://forge.smol.ai/docs/deploy/manifest-v1 | tail -3
    <div id="root"></div>
  </body>
</html>
```

2.9 KB shell, no content. Reading the spec required driving a real Chrome session. For a platform built for "AI-native workflows", the docs are the one thing agents can't fetch.

**5. `.md` suffix returns the SPA shell with HTTP 200.**
`/docs/deploy/manifest-v1.md` doesn't 404 — it silently serves HTML, so a fetcher can't detect the failure. The rendered page has a "Copy Markdown" / "Source" affordance, so the markdown exists; it just has no addressable URL.

**6. `app.entrypoint` semantics are ambiguous for framework builds.**
The spec describes it as "JavaScript or TypeScript source bundled by Forge's pinned compiler." For any framework with its own bundler (SolidStart/Nitro, SvelteKit, etc.) the natural entrypoint is an *already-bundled* output file. Whether Forge accepts that is still unknown. An example using a framework build output would settle it.

## CLI

**7. `--help` on a subcommand is ignored and the command runs anyway.**
`sf deploy check --help` executed the check instead of printing usage.

**8. Docs say `sf auth login`, but `sf` isn't on PATH.**
`@smolai/forge` installs as a devDependency, so the bin is local — it's `pnpm exec sf` / `npx smolforge`. The docs' bare `sf ...` invocations fail with `command not found` for anyone following them literally.

**9. No pull request commands in the CLI.**
For a "Forge CLI for coding agents," there's no `sf pr create` / `list` / `view`. PR creation is browser-only, which is the one thing an agent handles worst.

**10. `default_head_sha` is `null`** in `sf deploy list` → `release_status`, even though `main` has commits and pushes succeeded.

## Web UI

**11. The PR diff renders a 2-line insertion as +22 / −20.**
`git show` confirms `1 file changed, 2 insertions(+)`, LF endings unchanged, but the PR view shows the whole file replaced. Makes small PRs unreviewable.

**12. PR preview status surfaces a raw `Request failed (404)`.**
When no Deploy project exists, the PR page shows "Preview status unavailable — Request failed (404)" rather than "Deploy isn't configured for this repository."

**13. The Enable button silently no-ops right after project creation.**
The edit form collapses on create, so a click lands on a re-rendered element and does nothing — no error, no state change. You have to reopen via Edit and click again to get the real eligibility error.

**14. `/owner/repo/compare/main...branch` renders blank.**
The GitHub-compatible compare URL isn't supported (the real path is `/pulls/new`), and it fails as an empty page rather than a redirect or 404. Nice-to-have, not a bug — Forge never claimed that URL shape.

## Not a Forge issue, but worth a docs note

The build initially targeted the wrong runtime because Nitro defaults to the `node-server` preset, which emits a Node HTTP server rather than a Worker module. That's a SolidStart/Nitro default, not a Forge problem — but a docs line saying "your entrypoint must be Workers-compatible" would have caught it before a deploy attempt. The fix was `nitro({ preset: "cloudflare_module" })` in `vite.config.ts`, which emits to the same path so the manifest was unaffected.

## The manifest, for reference

Validates clean; never got to build.

```ts
import { defineForge } from '@smolai/forge/config';

export default defineForge({
  version: 1,
  name: 'forge-tester',
  build: { command: 'pnpm build', workingDirectory: '.' },
  app: { entrypoint: '.output/server/index.mjs' },
  routes: [{ pattern: '/*', to: 'app.http' }],
});
```

Versions: `@smolai/forge` 0.4.0-preview.0, `@solidjs/start` 2.0.0, nitro 3.0.260610-beta, vite 8.1.4, pnpm 10.33.0.