feat(ipfs2filecoin): add IPFS to Filecoin campaign landing page - #346
Conversation
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.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Adds a new campaign landing page at /ipfs2filecoin to act as the entry point for the IPFS→Filecoin mini-campaign, including client-side CID list checking, deposit estimation, an agent prompt CTA, and a served llms.txt migration brief.
Changes:
- Introduces the
/ipfs2filecoinpage composed from existingui-filecoincomponents, with SEO metadata + JSON-LD structured data. - Adds client-side utilities/components for CID list parsing, pricing comparison, and deposit estimation (with Plausible funnel events).
- Serves
/ipfs2filecoin/llms.txtastext/markdownand links it via metadata alternates for agent discovery.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/constants/paths.ts | Adds a PATHS.IPFS_TO_FILECOIN entry for the new route. |
| src/app/ipfs2filecoin/page.tsx | Implements the campaign landing page layout, content sections, and metadata alternates. |
| src/app/ipfs2filecoin/constants/seo.ts | Defines page SEO title/description. |
| src/app/ipfs2filecoin/utils/generate-structured-data.ts | Generates JSON-LD structured data for the campaign page. |
| src/app/ipfs2filecoin/constants/migration.ts | Centralizes campaign constants (caps, pricing inputs, llms.txt paths, Plausible event names). |
| src/app/ipfs2filecoin/utils/estimate-cost.ts | Implements pricing/deposit math and formatting helpers. |
| src/app/ipfs2filecoin/data/pricing-comparison.ts | Defines the comparison-table rows, including derived Filecoin $/TB/mo. |
| src/app/ipfs2filecoin/components/ComparisonTable.tsx | Renders the pricing comparison table UI. |
| src/app/ipfs2filecoin/components/CostEstimator.tsx | Client-side deposit estimator UI + Plausible event. |
| src/app/ipfs2filecoin/utils/parse-cid-list.ts | Parses/normalizes CID lists (strip gateway prefixes, validate, dedupe). |
| src/app/ipfs2filecoin/components/CidListChecker.tsx | Client-side CID list checker UI + cap routing + Plausible event. |
| src/app/ipfs2filecoin/components/AgentPrompt.tsx | Copy-to-clipboard agent prompt component + Plausible event. |
| src/app/ipfs2filecoin/data/reasons.ts | Defines “why migrate” card content. |
| src/app/ipfs2filecoin/data/steps.ts | Defines the “how it works” step cards. |
| src/app/ipfs2filecoin/data/limits.ts | Defines “what this does not do” limit statements. |
| src/app/ipfs2filecoin/data/faqs.tsx | Adds FAQ content for the landing page. |
| src/app/ipfs2filecoin/llms.txt/route.ts | Serves the llms.txt draft migration brief as markdown with caching headers. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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.
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.
fc86253 to
cc32d8e
Compare
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.
|
Restructure from today's product sync, flagged for design review with the rest of the PR: the agent prompt now leads in the hero, with the key-safety line and a jump link down to the checker. The paste box and its verdict moved beside the estimator under "What it costs", since paste and estimate are one interaction and now sit together. "How it works" moved directly under the hero this morning for the same reason: people asked to do the migration before being sold on it. The hero prompt copies report |
This reverts commit 65760e4.
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.
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.
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.
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.
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.
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.
Adds
filecoin.cloud/ipfs2filecoin, the front door for the IPFS-to-Filecoin mini-campaign.Ported from Jenni's wireframe onto the site's existing
ui-filecoincomponents, and reconciled against the PRD including its 2026-07-28 validation-run corrections.What's here
The page is the campaign's front door and its measuring instrument: it takes a pasted CID list, produces a deposit estimate from a declared volume, and routes to the agent door or to contact.
Everything interactive runs client-side with no wallet and no network calls, so a check costs the visitor nothing and sends us nothing.
/ipfs2filecoin/migrate.mdtext/markdown. (llms.txt was dropped per 2026-08-10 review: the runbook is the agent surface.)Instrumentation
Three Plausible events, matching the funnel the PRD asks for:
IPFS2Filecoin CID List Checked— with outcome and CID countIPFS2Filecoin Estimate Viewed— with volume, duration, depositIPFS2Filecoin Agent Prompt Copied— with source; the PRD calls this the headline numberPricing math
The estimator reproduces the PRD's worked example exactly — 1 TiB over two years:
The comparison table's $4.55/TB/month is also derived, from storage-only at 2 copies. Both fall out of constants in
constants/migration.ts, so a price change is a one-line edit that propagates to the table, the estimator, and the runbook together.Agent-readability
<link rel="alternate" type="text/markdown" href="…/migrate.md">is in the page head, so an agent pointed at the human URL finds the runbook without being told where it lives.The brief opens with a stage 0 ingress check — the validation run found runs die on missing public ingress after the expensive commP pass, so it gates before that, and tells the agent to stop and ask rather than install a tunnel binary on the user's behalf.
Copy rules
Followed the PRD's hard rules: sentence case, no emoji, second person, no
FOC/commP/PoDSI/aggregatein public copy, no implication that FilOz custodies anyone's data, no "cheapest" superlative, and no promise of an alert we have no channel to send.Decisions taken
Resolved since review
65760e4pointed the copied prompt at the branch preview for dogfooding; reverted in1acb395, so the prompt shipsfilecoin.cloud/ipfs2filecoin/migrate.md. That commit's stray blank line was also the failing biome check.864db7d, after a cross-agent review that caught four further defects in the first attempt (a key written into shell history, a rule the new key pattern contradicted, a bare prompt handed to lists over the inline cap, and a spending claim invalidated by moving signing to the agent).c161162). 0.9.0 is npmlatestas of 2026-09-01.--versionis the install check, and stage 5 reconciles withreport --jsoninstead of asking an agent to read a browser page. That closes the worst finding: on the upload pathreportcounted its own committed pieces as untracked and exited non-zero on a successful run, so an agent following this document reported good migrations as failed.gc-window.ts) and@filoz/synapse-core@0.8.1. No edit needed.afc8005). It named 2026-08-24, which was calibration's original target; that slipped to 08-31 and mainnet's PDP and FWSS upgrades land 09-03 (filecoin-services#597). The runbook defaults to mainnet, so it was endorsing reuse of data sets without the gas optimizations. Fresh sets are the default and are correct on every network regardless of timing. Jenni's "if all data set ids are below N" check still needs N, which does not exist until the mainnet upgrade lands.c2d4fad,48f31bb), deep-linked to the command-line walkthrough. filecoin-docs#2479 links back. Each link resolves when its counterpart merges; this repo's link checker is a weekly cron, not a PR gate, so the two can merge independently.Still open, none blocking
next.config.tsrewrites. Out of scope here; this PR is the landing page only, so there's no browser "check and fund" door yet.Dropped: the contact form
sourcefield. Campaign attribution already exists on chain, whereipfs2focstampssource: ipfs2filecoininto data set metadata at creation (confirmed in the dogfooding run's chain read). The form field would only separate inbound contact leads, on a low-volume overflow door, at the cost of adding an eighth field to the site-wide form.Verification
npm run lintandnpm run buildclean. Page andmigrate.mdroute verified against a production server locally, including the rendered agent prompt and the flat-fee figure.migrate.mdpasses the prose gate with no errors. One end-to-end mainnet migration run against this page and runbook, by a tester who was not the author.