Skip to content

fix(ipfs2filecoin): design review follow-ups for the landing page - #350

Merged
SgtPooki merged 13 commits into
FilOzone:feat/ipfs2filecoin-landing-pagefrom
gmoranxyz:ipfs2filecoin-design-review
Aug 14, 2026
Merged

fix(ipfs2filecoin): design review follow-ups for the landing page#350
SgtPooki merged 13 commits into
FilOzone:feat/ipfs2filecoin-landing-pagefrom
gmoranxyz:ipfs2filecoin-design-review

Conversation

@gmoranxyz

@gmoranxyz gmoranxyz commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

📝 Description

Design review follow-ups for /ipfs2filecoin, from a walkthrough of the page with @filipagr on 31 July, plus two rounds of polish since.

This targets feat/ipfs2filecoin-landing-page rather than main on purpose, so it feeds #346 instead of competing with it. Merging here means #346 carries the polish through to main as one piece.

Filipa's overall read was that the structure, content and calls to action are right — opening with "paste your CIDs" instead of a wall of reading is the correct choice. Almost everything below is layout and type hierarchy, plus one genuine functional gap and one drift risk.

  • Type: Bug fix

Two things to know before reviewing:

  1. This currently conflicts with the base, in src/app/ipfs2filecoin/page.tsx. The base branch has gained four commits this head doesn't have (bc84838 runbook rewrite for the direct-upload flow, abbe4ca flat data set fee charged once, b67a9fb unpin the CLI, 55dcabd re-verify competitor rates), and they touch the same file as the layout rework. CostEstimator.tsx, constants/migration.ts and data/pricing-comparison.ts all auto-merge; only page.tsx needs hand-resolving.
  2. The diff includes changes that aren't mine. This branch merged FilOzone:main, and the base is behind main, so the diff against the base also shows .github/CODEOWNERS (chore: set CODEOWNERS #349), the @filoz/synapse-sdk 1.1.1 bump (chore: update @filoz/synapse-sdk to v1.1.1 #348), and the temporary hiding of the Service Providers page with its redirect in next.config.ts (Temporarily hide the Service Providers page #347). Those aren't part of this work and will disappear once the base catches up with main. Reviewable scope is src/app/ipfs2filecoin/** plus src/components/{Accordion,Faq}.tsx and .gitignore.

🛠️ Key Changes

Three rounds, each commit scoped to one concern and independently revertable.

Round 1 — design review follow-ups (31 July)

fix(faq) — accordion dividers and chevrons were invisible. Faq hardcoded divide-white/20 and Accordion hardcoded text-zinc-200/text-zinc-300. All three assume a dark background, which held while the homepage was the only consumer; this page mounts the FAQ on a gray section, where they disappear. Now uses the --color-border-base / --color-text-base / --color-paragraph-text tokens, which already flip off the .light-section / .dark-section class Section sets — so no isDark branching was needed. Moving the colour onto the item rather than the parent also fixes the first divider: divide-* targets every child after the first, so item one's border was falling back to currentColor and rendering at full brightness on dark.

fix(ipfs2filecoin) — layout and type hierarchy.

  • The hero and "Estimate your deposit" sat 60px inset from their siblings: PageSection already wraps children in a Container and page.tsx nested a second one, doubling the horizontal padding.
  • Unit/Funded-for selects had the native arrow jammed against the border with a cavern between it and the value. Local SelectField goes appearance-none with a Phosphor caret inset to match the field's text.
  • Both tables move off text-sm to text-base, service names to text-lg.
  • Monospace figures dropped for the body font with tabular-nums.
  • Step numbers sit above each title in the accent colour, which needed a new StepList — the shared Card types title as a plain string, so the number could otherwise only be inlined as "01. Hand over the list".
  • Reason cards take Phosphor icons, following how agents/ and warm-storage-service/ already pass icons to Card.
  • The agent column takes two thirds with "Talk to us" as a one third call-out.
  • "What this does not do" constrained to max-w-5xl — lines ran past 15 words at desktop.

feat(ipfs2filecoin) — a checked CID list now produces something. parseCidList already validated, deduped and stripped gateway prefixes, but the verdict reported only a count, so the top of the page had no purpose — you still built cids.txt by hand. The prompt was in fact only offered on the over-cap branch, so the one outcome that succeeded was the one with no output. A checked list now yields the agent prompt with your own CIDs inlined via buildAgentPrompt, plus a cids.txt download of the cleaned list. AGENT_PROMPT stays as the fallback for the empty and over-cap cases, where pointing at a file is the right shape rather than inlining hundreds of lines. The instruction to "estimate what they cost to store below" is gone: a check reads the CIDs, not the bytes behind them, so it cannot price anything on its own.

chore — ignores CLAUDE.md and a local todo.md.

Round 2 — @filipagr's polish (#1, 3 August)

CID checker becomes one input surface. Label, textarea and action fold into a single bordered panel with a live "X of Y lines are CIDs" readout and a Cmd/Ctrl+Enter shortcut. The verdict moves into its own CidListVerdict component with an icon per outcome, and pluralize is extracted so the readout and the verdict agree.

Pricing table compares providers, not plan names. Each row gains a detail sub-line so the provider is what you compare on and the plan tier stays secondary, and rows are keyed by provider plus tier now that two Pinata tiers share a name. Below md the three columns don't fit, so each provider becomes a stacked card; the full table returns at md.

Estimator pairs with the table. It moves into a companion card beside the comparison table — the table is the market rate, the card prices it for your data — at lg:grid-cols-3 with the table on two columns and the estimator on one, its two inputs side by side and a compact stacked result that fits the narrow column. Also: a faint brand glow along the bottom of the hero (--color-brand-500 mixed to 12%, so it reads as light on the surface rather than a coloured panel), reason-card and agent-warning copy stepped down a size, and "How it works" four across at lg (2×2 from sm).

Round 3 — kill the hardcoded rate (#2, 5 August)

$2.50 was restated as a literal in the rate footnote, one reason card, and the SEO description, so all three could silently drift from the comparison table and estimator, which already derive from the constant. All now go through formatUsd(USD_PER_TIB_MONTH_PER_COPY).

📌 To-Do Before Merging

  • Resolve the conflict in page.tsx against the base's four newer commits. Worth doing as a merge of the base into this branch rather than a rebase, since the history is shared with @filipagr.
  • @filipagr — the monospace figures were dropped rather than resized. The reported problem was numbers looking larger than the service names beside them; that was a typeface illusion rather than a size difference, so matching the typeface removes it at the root while tabular-nums keeps the columns aligned. Still the most debatable call here, and easy to revert.
  • @filipagrAccordion/Faq are shared, so the homepage FAQ changes too: chevron zinc-200zinc-50, body zinc-300zinc-400. Both now match the site's own tokens, but worth eyeballing since it's outside this page's scope.
  • The external-link arrow beside Filebase/Pinata is fixed with a local override in page.tsx. It's sized for button text inside ExternalTextLink in ui-filecoin, so the real fix belongs upstream — worth a follow-up issue.

Closed since the original review: the hero background treatment, now handled by the brand glow rather than a produced asset; and table whitespace, which the responsive stacked cards and settled type sizes addressed.

Still not attempted, both needing a call rather than code:

  • The optional illustration beside "Nobody should migrate an archive by clicking" — Filipa's crowding caution stands.
  • Resolving a CID to its actual byte size, so the estimate reflects the real list rather than a number the user guesses. Needs backend capability and is a separate conversation.

🧪 How to Test

  • Setup: nvm use && npm install && npm run dev, then open /ipfs2filecoin.
  • Steps to Test:
    1. CID check. Paste a deliberately messy list into the hero panel — a bare CID, an https://ipfs.io/ipfs/… gateway URL, a duplicate, and a junk line. Watch the "X of Y lines are CIDs" readout as you type, then submit with Cmd/Ctrl+Enter rather than the button.
    2. Cost section. At lg the comparison table should occupy two thirds with the "Estimate your deposit" card beside it on one third, tops aligned. Narrow the window: the card drops below the table, and below md the table itself becomes one stacked card per provider.
    3. Pricing rows. Both Pinata tiers should render distinctly, each with its plan tier as a sub-line under the provider name.
    4. How it works. Four across at lg, 2×2 from sm, step numbers above each title in the accent colour.
    5. FAQ. Dividers and chevrons should be clearly visible against the gray section, including the divider above the first item. Compare with the homepage FAQ on its dark section.
    6. Hero. A faint blue lift along the bottom edge, carrying into the section below — not a visible panel edge.
  • Expected Results: step 1 resolves to the unique CIDs with the gateway prefix stripped, reports both the skipped line and the removed duplicate, and renders a prompt containing your actual CIDs plus a Download cids.txt link.
  • Verified: npm run build (TypeScript, twoslash'd Synapse snippet, all 25 routes) passes at 2a8113a, the PR Bump the dependencies group with 11 updates #1 merge. The head has since taken Build Main Components #2 and a main merge and hasn't been rebuilt locally — the conflict resolution will need a fresh build anyway.

📸 Screenshots

Verified in-browser at 1284px. Not attached here — CLI-created PR. Happy to add before/afters for the FAQ, the steps grid, the table/estimator pairing and the CID-check flow if useful.

🔖 Resources

🤖 Generated with Claude Code

gmoranxyz and others added 4 commits August 1, 2026 11:46
Faq hardcoded divide-white/20, and Accordion hardcoded text-zinc-200 on the
chevron and text-zinc-300 on the body. All three assume a dark background, which
held while the homepage was the only consumer since it mounts the FAQ on a dark
section. On a light or gray section the dividers and chevrons are effectively
invisible.

They now use --color-border-base, --color-text-base and --color-paragraph-text,
which flip off the .light-section / .dark-section class that Section already
sets, so no isDark branching is needed. Faq keeps useBackground purely for
prose-invert.

Moving the colour onto the item rather than the parent also fixes the first
divider. divide-* targets every child after the first, so item one's border was
falling back to currentColor and rendering at full brightness on dark.

The homepage FAQ shifts slightly as a result: chevron zinc-200 to zinc-50, body
zinc-300 to zinc-400, both now matching the tokens used everywhere else. That
page is worth a look alongside this one.

Review: @filipagr
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Follow-ups from a walkthrough of the page with Filipa Ribeiro.

Alignment and spacing

- "Estimate your deposit" and the hero sat 60px inset from their siblings,
  because PageSection already wraps children in a Container and page.tsx nested
  a second one, doubling the horizontal padding. Removed both, plus the
  now-unused import.
- The Unit and Funded-for selects had the native arrow jammed against the border
  with a cavern between it and the value. A local SelectField goes
  appearance-none with a Phosphor caret inset to match the field's text, and the
  grid drops from three equal columns to 2fr/1fr/2fr so Unit is no longer a
  full-width field holding three characters.
- "What this does not do" is constrained to max-w-5xl; lines ran past 15 words
  at desktop.

Type

- Both tables move off text-sm to text-base, with service names at text-lg.
- Monospace figures dropped for the body font with tabular-nums. The reported
  problem was numbers appearing larger than the names beside them, which was a
  typeface illusion rather than a size difference, so matching the typeface
  removes it at the root while tabular-nums keeps the columns aligned. Flagging
  this one as the most debatable call in the batch.
- The highlighted Filecoin row carries weight instead of a marginally darker
  grey, which read as a mistake rather than emphasis.

Visual interest

- How it works renders 2x2 rather than 3-up with an orphaned fourth, and step
  numbers sit above each title in the accent colour. This needs a new StepList
  component because the shared Card types title as a plain string, so the number
  could only ever be inlined as "01. Hand over the list".
- Reason cards take icons, following how agents/ and warm-storage-service/
  already pass Phosphor icons to Card.
- The agent column takes two thirds and "Talk to us" becomes a one third
  call-out, giving the path with more to say more room.

The external-link arrow beside Filebase and Pinata is tightened with a local
override. It is sized for button text inside ExternalTextLink in ui-filecoin, so
the real fix belongs upstream; this is a commented stopgap.

Still open from the review and deliberately not attempted here: table whitespace
now that the type sizes are settled, the hero background treatment, and the
optional illustration beside the agent heading.

Review: @filipagr
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
parseCidList already validated, deduped and stripped gateway prefixes, but the
verdict box reported only a count. The successful path gave you nothing to act
on, so the top of the page had no purpose: you still assembled cids.txt by hand.
The prompt was in fact offered only on the over-cap branch, so the one outcome
that succeeded was the one outcome with no output.

A checked list now produces the agent prompt with your own CIDs inlined, via
buildAgentPrompt, plus a cids.txt download of the cleaned and deduped list.
AGENT_PROMPT stays as the fallback for the empty and over-cap cases, where
pointing at a file is the right shape rather than inlining hundreds of lines.

The instruction to "estimate what they cost to store below" is replaced. A check
reads the CIDs and not the bytes behind them, so it cannot price anything on its
own, and implying otherwise was the most confusing part of the flow. Resolving a
CID to its actual size needs backend capability and is a separate conversation.

Hero polish in the same component: "one per line" sits beside the label in the
accent colour rather than surfacing only after a failed check, the button is
centred, the empty textarea is shorter, and the free-check facts read as a
scannable list instead of fine print. Copy prompt demotes from a full-width
button to an icon in the code block's corner.

Verified against deliberately messy input: a bare CID, a gateway URL, a
duplicate and a junk line resolve to three unique CIDs, with the URL prefix
stripped and both the skipped line and the duplicate reported.

Review: @filipagr
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CLAUDE.md is per-machine guidance for Claude Code, and todo.md is the working
list of design review actions for /ipfs2filecoin. Neither belongs in the repo.

Note that this keeps todo.md local, so it does not travel to reviewers via git.

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

vercel Bot commented Aug 1, 2026

Copy link
Copy Markdown

@gmoranxyz is attempting to deploy a commit to the FilOz Team on Vercel.

A member of the Team first needs to authorize it.

@FilOzzy FilOzzy added this to FOC Aug 1, 2026
@github-project-automation github-project-automation Bot moved this to 📌 Triage in FOC Aug 1, 2026
@gmoranxyz
gmoranxyz marked this pull request as draft August 1, 2026 10:49
@gmoranxyz

Copy link
Copy Markdown
Contributor Author

@filipagr take a look and let me know what you think as a first pass!

filipagr and others added 3 commits August 3, 2026 19:47
Fold the label, textarea and action into a single bordered panel with a live "X of Y lines are CIDs" readout and a Cmd/Ctrl+Enter shortcut. Move the verdict into its own CidListVerdict component with an icon per outcome, and extract pluralize so the readout and verdict agree.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… responsive

Give each pricing row a detail sub-line so the provider is what you compare on and the plan tier stays secondary, and key rows by provider plus tier now that two Pinata tiers share a name. On mobile the three columns do not fit, so each provider becomes a stacked card; the full table returns at md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… hero and type

Move the estimator into a companion card beside the comparison table (the table is the market rate, the card prices it for your data), with the two inputs side by side and a compact stacked result that fits the narrow column. Add a faint brand glow along the bottom of the hero, step the reason-card and agent-warning copy down a size, and render How it works four across on desktop.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
gmoranxyz and others added 4 commits August 5, 2026 14:36
fix(ipfs2filecoin): estimator beside the table, responsive pricing, hero polish
…COPY

The rate footnote, one reason card, and the SEO description each restated
$2.50 as a literal, so they could silently drift from the comparison table
and estimator, which already derive from the constant.
fix(ipfs2filecoin): derive the $2.50 rate from USD_PER_TIB_MONTH_PER_COPY
@gmoranxyz
gmoranxyz marked this pull request as ready for review August 5, 2026 14:30
@gmoranxyz

Copy link
Copy Markdown
Contributor Author

@jennijuju I think this is ready for you to take a look! Please forgive anything we broke with our clumsy vibe coding!

@github-project-automation github-project-automation Bot moved this from 📌 Triage to ✔️ Approved by reviewer in FOC Aug 14, 2026
@SgtPooki
SgtPooki merged commit 4b57966 into FilOzone:feat/ipfs2filecoin-landing-page Aug 14, 2026
5 checks passed
@github-project-automation github-project-automation Bot moved this from ✔️ Approved by reviewer to 🎉 Done in FOC Aug 14, 2026
SgtPooki added a commit that referenced this pull request Sep 1, 2026
* fix(faq): make accordion dividers and chevrons background-aware

Faq hardcoded divide-white/20, and Accordion hardcoded text-zinc-200 on the
chevron and text-zinc-300 on the body. All three assume a dark background, which
held while the homepage was the only consumer since it mounts the FAQ on a dark
section. On a light or gray section the dividers and chevrons are effectively
invisible.

They now use --color-border-base, --color-text-base and --color-paragraph-text,
which flip off the .light-section / .dark-section class that Section already
sets, so no isDark branching is needed. Faq keeps useBackground purely for
prose-invert.

Moving the colour onto the item rather than the parent also fixes the first
divider. divide-* targets every child after the first, so item one's border was
falling back to currentColor and rendering at full brightness on dark.

The homepage FAQ shifts slightly as a result: chevron zinc-200 to zinc-50, body
zinc-300 to zinc-400, both now matching the tokens used everywhere else. That
page is worth a look alongside this one.

Review: @filipagr

* fix(ipfs2filecoin): correct layout and type hierarchy from design review

Follow-ups from a walkthrough of the page with Filipa Ribeiro.

Alignment and spacing

- "Estimate your deposit" and the hero sat 60px inset from their siblings,
  because PageSection already wraps children in a Container and page.tsx nested
  a second one, doubling the horizontal padding. Removed both, plus the
  now-unused import.
- The Unit and Funded-for selects had the native arrow jammed against the border
  with a cavern between it and the value. A local SelectField goes
  appearance-none with a Phosphor caret inset to match the field's text, and the
  grid drops from three equal columns to 2fr/1fr/2fr so Unit is no longer a
  full-width field holding three characters.
- "What this does not do" is constrained to max-w-5xl; lines ran past 15 words
  at desktop.

Type

- Both tables move off text-sm to text-base, with service names at text-lg.
- Monospace figures dropped for the body font with tabular-nums. The reported
  problem was numbers appearing larger than the names beside them, which was a
  typeface illusion rather than a size difference, so matching the typeface
  removes it at the root while tabular-nums keeps the columns aligned. Flagging
  this one as the most debatable call in the batch.
- The highlighted Filecoin row carries weight instead of a marginally darker
  grey, which read as a mistake rather than emphasis.

Visual interest

- How it works renders 2x2 rather than 3-up with an orphaned fourth, and step
  numbers sit above each title in the accent colour. This needs a new StepList
  component because the shared Card types title as a plain string, so the number
  could only ever be inlined as "01. Hand over the list".
- Reason cards take icons, following how agents/ and warm-storage-service/
  already pass Phosphor icons to Card.
- The agent column takes two thirds and "Talk to us" becomes a one third
  call-out, giving the path with more to say more room.

The external-link arrow beside Filebase and Pinata is tightened with a local
override. It is sized for button text inside ExternalTextLink in ui-filecoin, so
the real fix belongs upstream; this is a commented stopgap.

Still open from the review and deliberately not attempted here: table whitespace
now that the type sizes are settled, the hero background treatment, and the
optional illustration beside the agent heading.

Review: @filipagr

* feat(ipfs2filecoin): turn a checked CID list into something actionable

parseCidList already validated, deduped and stripped gateway prefixes, but the
verdict box reported only a count. The successful path gave you nothing to act
on, so the top of the page had no purpose: you still assembled cids.txt by hand.
The prompt was in fact offered only on the over-cap branch, so the one outcome
that succeeded was the one outcome with no output.

A checked list now produces the agent prompt with your own CIDs inlined, via
buildAgentPrompt, plus a cids.txt download of the cleaned and deduped list.
AGENT_PROMPT stays as the fallback for the empty and over-cap cases, where
pointing at a file is the right shape rather than inlining hundreds of lines.

The instruction to "estimate what they cost to store below" is replaced. A check
reads the CIDs and not the bytes behind them, so it cannot price anything on its
own, and implying otherwise was the most confusing part of the flow. Resolving a
CID to its actual size needs backend capability and is a separate conversation.

Hero polish in the same component: "one per line" sits beside the label in the
accent colour rather than surfacing only after a failed check, the button is
centred, the empty textarea is shorter, and the free-check facts read as a
scannable list instead of fine print. Copy prompt demotes from a full-width
button to an icon in the code block's corner.

Verified against deliberately messy input: a bare CID, a gateway URL, a
duplicate and a junk line resolve to three unique CIDs, with the URL prefix
stripped and both the skipped line and the duplicate reported.

Review: @filipagr

* chore: ignore local agent and working files

CLAUDE.md is per-machine guidance for Claude Code, and todo.md is the working
list of design review actions for /ipfs2filecoin. Neither belongs in the repo.

Note that this keeps todo.md local, so it does not travel to reviewers via git.

Review: @filipagr

* feat(ipfs2filecoin): rework the CID checker into one input surface

Fold the label, textarea and action into a single bordered panel with a live "X of Y lines are CIDs" readout and a Cmd/Ctrl+Enter shortcut. Move the verdict into its own CidListVerdict component with an icon per outcome, and extract pluralize so the readout and verdict agree.


* fix(ipfs2filecoin): split provider from tier and make the price table responsive

Give each pricing row a detail sub-line so the provider is what you compare on and the plan tier stays secondary, and key rows by provider plus tier now that two Pinata tiers share a name. On mobile the three columns do not fit, so each provider becomes a stacked card; the full table returns at md.


* fix(ipfs2filecoin): pair the deposit estimator with the table, refine hero and type

Move the estimator into a companion card beside the comparison table (the table is the market rate, the card prices it for your data), with the two inputs side by side and a compact stacked result that fits the narrow column. Add a faint brand glow along the bottom of the hero, step the reason-card and agent-warning copy down a size, and render How it works four across on desktop.


* fix(ipfs2filecoin): derive the $2.50 rate from USD_PER_TIB_MONTH_PER_COPY

The rate footnote, one reason card, and the SEO description each restated
$2.50 as a literal, so they could silently drift from the comparison table
and estimator, which already derive from the constant.

---------

Co-authored-by: filipagr <filipagoncalvesribeiro@gmail.com>
Co-authored-by: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com>
SgtPooki added a commit that referenced this pull request Sep 1, 2026
* feat(ipfs2filecoin): add IPFS to Filecoin campaign landing page

Adds filecoin.cloud/ipfs2filecoin, the front door for the IPFS-to-Filecoin
mini-campaign, ported from Jenni's wireframe in FilOzone/FOC-PM onto the
site's existing ui-filecoin components.

The page is both the campaign's front door and its measuring instrument. It
does three things: takes a pasted CID list, produces a deposit estimate from a
declared volume, and routes to the agent door or to contact.

Interactive parts run entirely client-side, with no wallet and no network
calls, so a check costs the visitor nothing and sends us nothing:

- CID list checker: validates, dedupes, and steers lists over the 500-item
  browser cap to the agent prompt.
- Deposit estimator: reproduces the PRD's worked example exactly ($128.08
  deposit, $5.25 refundable for 1 TiB over two years) from documented
  constants rather than hardcoded figures.
- Agent prompt with copy-to-clipboard, the primary conversion.

Plausible events cover the funnel the PRD asks for: CID List Checked,
Estimate Viewed, and Agent Prompt Copied, the last being the headline number.

Also serves a draft migration brief at /ipfs2filecoin/llms.txt and advertises
it via <link rel="alternate" type="text/markdown">, so an agent pointed at the
human URL discovers the brief without being told the convention. The brief
opens with a stage 0 ingress check, per the 2026-07-28 validation run that
found runs die there after the expensive commP pass.

The page is unlinked from site navigation, reachable by URL and sitemap only,
so campaign attribution stays clean.

* feat(ipfs2filecoin): replace the draft brief with an executable runbook

A real agent run against the draft brief failed at the first hop: the brief
never named the tool, so the agent correctly refused to improvise a pipeline
and stopped. It also read the 500 GiB figure as a self-serve cap and routed a
56k-CID job to the contact form, which killed the conversion outright.

Both are fixed, and the format question behind them is settled.

llms.txt was the wrong format. Per llmstxt.org it is a documentation index --
H1, blockquote, then H2 lists of links -- so a procedure does not belong in
it. The procedure now lives at /ipfs2filecoin/migrate.md, named for what it
is, and llms.txt is used correctly in two places: a spec-conformant site
index at /llms.txt, and a campaign index at /ipfs2filecoin/llms.txt whose
first link is the runbook. Discovery never depended on the filename anyway --
the prompt carries the URL, and the page carries rel="alternate".

The runbook names ipfs2foc, pins the version its flags were verified against,
and carries the real command sequence read out of that repo. Notable content:

- One invocation form, stated once. A bare `ipfs2foc` after only an `npx`
  check was the most likely first failure.
- Prerequisites split into "needed now" and "needed before stage 4", so a
  missing key no longer blocks the free stages.
- Stage 0 settles ingress before the commitment pass, and records that the
  relay only serves the single-asset path.
- Stage 2 reports from analyze --json using fields that actually exist, with
  explicit cost and ETA formulas so nothing is invented.
- Stage 4 is executed by the user in their own terminal. The agent is told
  never to accept a private key -- a key pasted into a chat is a key in a
  transcript.
- Stage 5 spawns the pull source as a background process and extracts the
  tunnel URL from its log, rather than saying "terminal A".
- Duration is framed as expected, not as a limit: a long-running command is
  working, not hung, and there is no cap on CID count.

Page copy follows: SELF_SERVE_VOLUME_CAP_LABEL becomes
COORDINATION_VOLUME_LABEL and reads as coordination rather than a ceiling, so
an agent reading the page cannot reproduce the original false blocker.

Reviewed by Codex and Gemini via the peer-review skill; every finding above
came out of that pass. Cursor could not run -- it needs auth.

* fix(ipfs2filecoin): correct two runbook claims the CLI does not support

Audited every command and flag in the runbook against the USAGE string in
ipfs2foc's packages/cli/src/index.ts, which is authoritative. Two were wrong.

`ipfs2foc --version` is not a subcommand. It falls through to the default
branch, writes "unknown command: --version" to stderr, and sets exit code 1.
As the very first step of the runbook that reads like a broken install, which
is exactly the first-hop failure this rewrite exists to remove. The install
check is now `--help`, with a note saying why.

The provider's minimum piece size is advisory, not enforced. `pdp-submit`
warns and proceeds by default and only refuses under `--strict-piece-size`
(see submit-pdp.ts: "The advertised floor is advisory in practice"). The
runbook claimed items below the minimum fail at pull time, which would have
pushed agents onto the multi-asset path unnecessarily -- it needs staging disk
and rules out the relay. Now stated as the trade it is: the minimum is a
packing efficiency question, the pull limit is the hard one.

* chore(ipfs2filecoin): re-verify competitor rates

Checked all four rows against filebase.com/pricing and pinata.cloud/pricing.
Every rate still matches: Filebase Pro storage $0.015/GB and IPFS egress
$0.015/GB; Pinata Fiesta $0.035/GB and $0.080/GB; Pinata Picnic $0.070/GB
and $0.100/GB.

No figures changed. The verification date lives in the source comment rather
than on the page: it is a maintenance note for us, it ages badly in public,
and the two pricing links already let a reader check the current numbers.

* fix(ipfs2filecoin): stop pinning the CLI to an unpublished version

The runbook told agents to run `npm install -g ipfs2foc@0.6.0`. npm has only
0.1.0 through 0.4.0, so that resolves to nothing and fails with ETARGET on
the first command of the procedure. 0.6.0 is the in-tree version; the repo
runs ahead of what has been released.

Installing latest is correct and safe here. I unpacked the published 0.4.0
and checked its bundle directly: all fourteen commands the runbook uses are
present (analyze, commp, create-data-set, export, gas, import-manifest,
pack-cars, pdp-submit, plan, probe, redirect-serve, report, serve, status),
as is every flag it passes, including --strict-piece-size, --ingress,
--source-relay, --no-auto-pack, --sample and --car-store. 0.4.0 also has no
--version subcommand, so the --help install check holds there too.

The frontmatter now carries tool_min_version rather than an exact pin, since
what an agent needs to know is the floor, not the version someone happened
to verify against.

* fix(ipfs2filecoin): add the flat data set fee once, not per TiB

* feat(ipfs2filecoin): rewrite the runbook for the direct-upload flow

* fix(ipfs2filecoin): design review follow-ups for the landing page (#350)

* fix(faq): make accordion dividers and chevrons background-aware

Faq hardcoded divide-white/20, and Accordion hardcoded text-zinc-200 on the
chevron and text-zinc-300 on the body. All three assume a dark background, which
held while the homepage was the only consumer since it mounts the FAQ on a dark
section. On a light or gray section the dividers and chevrons are effectively
invisible.

They now use --color-border-base, --color-text-base and --color-paragraph-text,
which flip off the .light-section / .dark-section class that Section already
sets, so no isDark branching is needed. Faq keeps useBackground purely for
prose-invert.

Moving the colour onto the item rather than the parent also fixes the first
divider. divide-* targets every child after the first, so item one's border was
falling back to currentColor and rendering at full brightness on dark.

The homepage FAQ shifts slightly as a result: chevron zinc-200 to zinc-50, body
zinc-300 to zinc-400, both now matching the tokens used everywhere else. That
page is worth a look alongside this one.

Review: @filipagr

* fix(ipfs2filecoin): correct layout and type hierarchy from design review

Follow-ups from a walkthrough of the page with Filipa Ribeiro.

Alignment and spacing

- "Estimate your deposit" and the hero sat 60px inset from their siblings,
  because PageSection already wraps children in a Container and page.tsx nested
  a second one, doubling the horizontal padding. Removed both, plus the
  now-unused import.
- The Unit and Funded-for selects had the native arrow jammed against the border
  with a cavern between it and the value. A local SelectField goes
  appearance-none with a Phosphor caret inset to match the field's text, and the
  grid drops from three equal columns to 2fr/1fr/2fr so Unit is no longer a
  full-width field holding three characters.
- "What this does not do" is constrained to max-w-5xl; lines ran past 15 words
  at desktop.

Type

- Both tables move off text-sm to text-base, with service names at text-lg.
- Monospace figures dropped for the body font with tabular-nums. The reported
  problem was numbers appearing larger than the names beside them, which was a
  typeface illusion rather than a size difference, so matching the typeface
  removes it at the root while tabular-nums keeps the columns aligned. Flagging
  this one as the most debatable call in the batch.
- The highlighted Filecoin row carries weight instead of a marginally darker
  grey, which read as a mistake rather than emphasis.

Visual interest

- How it works renders 2x2 rather than 3-up with an orphaned fourth, and step
  numbers sit above each title in the accent colour. This needs a new StepList
  component because the shared Card types title as a plain string, so the number
  could only ever be inlined as "01. Hand over the list".
- Reason cards take icons, following how agents/ and warm-storage-service/
  already pass Phosphor icons to Card.
- The agent column takes two thirds and "Talk to us" becomes a one third
  call-out, giving the path with more to say more room.

The external-link arrow beside Filebase and Pinata is tightened with a local
override. It is sized for button text inside ExternalTextLink in ui-filecoin, so
the real fix belongs upstream; this is a commented stopgap.

Still open from the review and deliberately not attempted here: table whitespace
now that the type sizes are settled, the hero background treatment, and the
optional illustration beside the agent heading.

Review: @filipagr

* feat(ipfs2filecoin): turn a checked CID list into something actionable

parseCidList already validated, deduped and stripped gateway prefixes, but the
verdict box reported only a count. The successful path gave you nothing to act
on, so the top of the page had no purpose: you still assembled cids.txt by hand.
The prompt was in fact offered only on the over-cap branch, so the one outcome
that succeeded was the one outcome with no output.

A checked list now produces the agent prompt with your own CIDs inlined, via
buildAgentPrompt, plus a cids.txt download of the cleaned and deduped list.
AGENT_PROMPT stays as the fallback for the empty and over-cap cases, where
pointing at a file is the right shape rather than inlining hundreds of lines.

The instruction to "estimate what they cost to store below" is replaced. A check
reads the CIDs and not the bytes behind them, so it cannot price anything on its
own, and implying otherwise was the most confusing part of the flow. Resolving a
CID to its actual size needs backend capability and is a separate conversation.

Hero polish in the same component: "one per line" sits beside the label in the
accent colour rather than surfacing only after a failed check, the button is
centred, the empty textarea is shorter, and the free-check facts read as a
scannable list instead of fine print. Copy prompt demotes from a full-width
button to an icon in the code block's corner.

Verified against deliberately messy input: a bare CID, a gateway URL, a
duplicate and a junk line resolve to three unique CIDs, with the URL prefix
stripped and both the skipped line and the duplicate reported.

Review: @filipagr

* chore: ignore local agent and working files

CLAUDE.md is per-machine guidance for Claude Code, and todo.md is the working
list of design review actions for /ipfs2filecoin. Neither belongs in the repo.

Note that this keeps todo.md local, so it does not travel to reviewers via git.

Review: @filipagr

* feat(ipfs2filecoin): rework the CID checker into one input surface

Fold the label, textarea and action into a single bordered panel with a live "X of Y lines are CIDs" readout and a Cmd/Ctrl+Enter shortcut. Move the verdict into its own CidListVerdict component with an icon per outcome, and extract pluralize so the readout and verdict agree.


* fix(ipfs2filecoin): split provider from tier and make the price table responsive

Give each pricing row a detail sub-line so the provider is what you compare on and the plan tier stays secondary, and key rows by provider plus tier now that two Pinata tiers share a name. On mobile the three columns do not fit, so each provider becomes a stacked card; the full table returns at md.


* fix(ipfs2filecoin): pair the deposit estimator with the table, refine hero and type

Move the estimator into a companion card beside the comparison table (the table is the market rate, the card prices it for your data), with the two inputs side by side and a compact stacked result that fits the narrow column. Add a faint brand glow along the bottom of the hero, step the reason-card and agent-warning copy down a size, and render How it works four across on desktop.


* fix(ipfs2filecoin): derive the $2.50 rate from USD_PER_TIB_MONTH_PER_COPY

The rate footnote, one reason card, and the SEO description each restated
$2.50 as a literal, so they could silently drift from the comparison table
and estimator, which already derive from the constant.

---------

Co-authored-by: filipagr <filipagoncalvesribeiro@gmail.com>
Co-authored-by: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com>

* fix(ipfs2filecoin): drop llms.txt links to the hidden service-providers page

* fix(ipfs2filecoin): accept subdomain-style gateway URLs in the CID checker

* fix(ipfs2filecoin): describe resumability as the CLI state database, not a browser tab

* fix(ipfs2filecoin): runbook requires Node 24 per ipfs2foc 0.8.1

* feat(ipfs2filecoin): drop the 500-item browser check cap

* feat(ipfs2filecoin): remove llms.txt routes, the runbook at migrate.md is the agent surface

* feat(ipfs2filecoin): carry the agent prompt in the runbook itself

* perf(ipfs2filecoin): single-pass CID list parse

* docs(ipfs2filecoin): steer agents off pre-upgrade data sets

* docs(ipfs2filecoin): disclose CLI telemetry in runbook

* feat(ipfs2filecoin): state the list stays in the browser

* fix(ipfs2filecoin): dedupe trust line with the fact chips

* fix(ipfs2filecoin): keep the check button on one line

* feat(ipfs2filecoin): apply product-sync feedback

* feat(ipfs2filecoin): lead with the agent prompt

* fix(ipfs2filecoin): close with the promised actions

* chore(ipfs2filecoin): point prompt at the preview

* fix(ipfs2filecoin): drop the last testnet mention

* docs(ipfs2filecoin): disclose upload totals telemetry

* Revert "chore(ipfs2filecoin): point prompt at the preview"

This reverts commit 65760e4.

* fix(ipfs2filecoin): close dogfooding-run findings

From James's 2026-08-28 mainnet run of the page and runbook.

The hero prompt gave an agent no input, so it stalled on the first
turn asking for CIDs. Over the inline cap the checker's prompt fell
back to that same bare line while the copy beside it claimed the
prompt read from a file; it now names cids.txt.

The FAQ said the agent hands back both funding and signing. The
runbook and the hero say it signs. Funding and placing the key are
the user's; signing is not.

Stage 4 needs a key in an environment an agent's shell does not keep
between commands, and nothing documented how to get one there. It
now reads the key from a file without resolving it, written with a
prompt rather than a literal so it stays out of shell history. Rule
3 stated an invariant that pattern would have broken.

Four promises of a manifest had no referent: nothing writes one.
Replaced with the artifacts the run actually produces.

The flat per-data-set fee is 0.024 and rendered as $0.02, understating
it by up to 17% below ~100 GiB. Rates now format to three decimals;
totals still fix at two, so the deposit table is unchanged. Volumes
under a gibibyte could not be entered at all.

* docs(ipfs2filecoin): tighten the runbook's key rule

State the permitted move first. A rule built only of prohibitions
puts the forbidden action in front of the agent and never names the
one it should take, and the frontmatter's never-list contradicted the
key-file pattern stage 3 now documents.

Also drops em-dashes from the added comments and prose.

* feat(ipfs2filecoin): link the docs migration guide

The reciprocal half of the cross-link agreed in the product sync;
filecoin-docs#2479 points back here. The runbook is the agent's copy
of the migration, so the FAQ about what an agent does is where
someone deciding to run it by hand will be standing.

The URL resolves once #2479 merges, as ours does for theirs.

* docs(ipfs2filecoin): move the runbook to ipfs2foc 0.9.0

0.9.0 is now npm latest, so the two things the runbook worked around
are gone.

The install check is `--version`, which reports what it installed
rather than only proving the binary resolves.

Stage 5 reconciles onchain with `report --json`. It used to send the
agent to a browser page it could not open, and `report` was unusable
anyway: on the upload path it counted its own committed pieces as
untracked and exited non-zero on a successful run, so an agent
following this document would report a good migration as failed. The
explorer link stays for the human.

* fix(ipfs2filecoin): drop the wrong data-set upgrade date

The runbook told agents a data set created after 2026-08-24 has the
gas optimizations. That date is calibration's original target, which
itself slipped to 08-31, and mainnet's PDP and FWSS upgrades are not
scheduled until 09-03 (filecoin-services#597). The runbook defaults
to mainnet, so it was telling agents to reuse mainnet data sets that
do not have the optimizations.

Fresh sets are already the default and are correct on every network
regardless of upgrade timing, so the guidance now rests on that
rather than on a date that differs per network and keeps moving.

* fix(ipfs2filecoin): deep-link the docs walkthrough

The FAQ offers the migration "written out step by step", which is
command-line.md. The guide's landing page it pointed at is conceptual,
so the link undersold what it promised by one click.

---------

Co-authored-by: G <gmoran651@gmail.com>
Co-authored-by: filipagr <filipagoncalvesribeiro@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 🎉 Done

Development

Successfully merging this pull request may close these issues.

5 participants