Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions marketing/cowork/inbox/2026-09-08-v0-1-0-devto.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"_meta": {
"campaign": "threadplane-0-1-0",
"channel_note": "Day 2. canonicalUrl points at the blog so the blog keeps SEO credit. Deliberately NOT a copy of the blog post: this leads with the 'where it stops' section, which is the most Dev.to-native angle. Attach og-card (1200x630) as cover at post time. DRY_RUN=1 smoke first.",
"review_status": "awaiting-brian"
},
"draft": {
"channel": "devto",
"article": {
"title": "The most useful part of our release notes is the list of things we refuse to do for you",
"tags": [
"angular",
"opensource",
"ai",
"webdev"
],
"canonicalUrl": "https://threadplane.ai/blog/threadplane-0-1-0",
"description": "Threadplane 0.1.0 is out \u2014 an MIT Angular framework for agent UIs on LangGraph and AG-UI. The section worth reading first is the one that says where the library stops."
},
"text": "Threadplane 0.1.0 shipped this week. It is an Angular framework for building agent UIs on LangGraph and AG-UI, it is MIT, and every capability is in the free tier because there is no other tier.\n\nI want to write about one section of the release notes instead of the whole list, because it is the section I would read first if someone handed me this library.\n\n## The list that says where it stops\n\nHere is what Threadplane does **not** do for you, and will not quietly start doing in a patch release:\n\n- **The agent endpoint sits behind your proxy.** The browser should not talk to your graph server directly.\n- **API keys never reach the bundle.** There is no config option that makes this safe, so there is no config option.\n- **Thread IDs are server-generated.** Never mint one client-side.\n- **CORS is yours to configure.**\n- **The interrupt panel is yours to compose.** `<chat>` does not render it. The primitives ship; the review experience is a product decision.\n- **The resume payload is yours to choose.** Only you know what \"approved\" means in your domain.\n- **Tracing and evaluation are yours.** Runs get traced by tools built for tracing, not by a UI library.\n\nA feature list is a sales document unless it also says where it stops. Every row above is a place where taking the work off your hands would mean taking a decision off your hands too \u2014 and the ones I would most regret automating are the security ones.\n\n## What it does do\n\nThe pitch is narrow on purpose: the last mile. Everything between \"my agent streams tokens\" and \"my team can put this in front of a customer.\"\n\n- `<chat>` plus 15 documented components \u2014 message list, input, tool-call cards, reasoning, trace, subagent cards, sidebar, popup, debug\n- Streaming markdown over a 26-node registry, sanitized, with per-instance overrides\n- Durable threads: persistence, checkpoints, durable execution, time travel\n- Interrupts and human approvals\n- Client tools that run in the browser and hand control back to the graph\n- Generative UI via json-render and A2UI v0.9, rendering only components you registered\n- Subagents as their own cards with their own transcripts\n- The five Deep Agents capabilities \u2014 planning, filesystem, subagents, memory, skills\n- `AgentError` classifying every failure as `connection`, `auth`, `server`, `interrupted`, or `aborted`, each with a `retryable` flag\n- A test path that runs with no model and no API key\n\n## The runtime is not a one-way door\n\n`@threadplane/langgraph` and `@threadplane/ag-ui` both produce the same `Agent` interface \u2014 six signals, four methods, one event stream. Components written against `<chat>` do not know which backend they are talking to. When the backend changes, your providers change and your components do not.\n\nI measured that rather than asserting it. Across three capability demos built twice, the same six of nine files differ every time, and four of those six are not application code.\n\nThe AG-UI side is protocol-first, so it got tested against runtimes that have nothing to do with LangGraph: AWS Strands, Microsoft Agent Framework, and Mastra. Three runtimes, two languages, no adapter changes for messages, tool calls, or state. Each has a standalone example and a committed transcript of its wire traffic.\n\n## About the version number\n\nThrough `v0.0.66` this project bumped only the patch digit. Fifty-five commits of accumulated breaking changes shipped under a counter that said nothing had broken.\n\nThat is not semver, and by the end the published packages were contradicting the documentation. So 0.1.0 is not a feature release. It is the release where the version number starts telling the truth. Six packages move as one fixed group, because an adapter and the surface it feeds are not independently upgradable in practice.\n\n## The free part\n\nThere is no open-core split. No capability is held back, no seat count, no activation, no runtime license check, no account.\n\nThere are paid offerings and I want to be precise about what they sell: review time, a private channel, and a response commitment. They sell my attention. They do not sell code you cannot otherwise have.\n\nThe moment a capability moves behind a paywall, every architectural decision in the library starts getting made by the pricing page, and you can feel that in the code long before you see it on the invoice.\n\nTry it without a backend first \u2014 it runs a fake agent in the browser, so you can see the UI before you stand up a server:\n\n```bash\nnpm install @threadplane/chat @threadplane/langgraph @langchain/core @langchain/langgraph-sdk marked\n```\n\nFull write-up with the complete capability table: https://threadplane.ai/blog/threadplane-0-1-0\n\nIf you try it, I would rather hear where it broke than that it was nice."
}
}
145 changes: 145 additions & 0 deletions marketing/cowork/inbox/2026-09-08-v0-1-0-launch-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Threadplane 0.1.0 — launch plan

> Campaign: `threadplane-0-1-0`. Anchor: <https://threadplane.ai/blog/threadplane-0-1-0>
> Voice: `docs/gtm/voice.md`. Claims: `docs/gtm/messaging.md`. Audience: `docs/gtm/icp.md`.
> Copy lives in the sibling files: `-x.json`, `-devto.json`, `-manual-channels.md`.
> Status: **awaiting-brian**. Nothing posts until each draft is reviewed.

## The problem with this announcement

"We released version 0.1.0" is not a story. Nobody outside the repository cares that a
number moved, and on Hacker News a version-bump post is downvoted as promotion before
anyone reads it.

The campaign works only if each channel gets the angle that channel actually rewards.
There are three real stories in this release, and the plan assigns them deliberately
rather than repeating the same paragraph five times.

| Angle | What it says | Best channel |
|---|---|---|
| **The version number was lying** | 55 commits of breaking changes shipped under a patch counter. 0.1.0 is the correction. | Hacker News |
| **The last mile is complete, and free** | Every capability, MIT, no paywalled tier, no account. | X, Discord, LinkedIn |
| **Where it stops** | The proxy, the keys, the interrupt panel, tracing — still yours, on purpose. | r/Angular, Dev.to |

The first angle is the one I would lead with anywhere technical. It is self-critical,
it is specific, and versioning is a subject engineers argue about for free. A confession
travels where an announcement does not.

## Sequence

Front-load the channels we control, let HN and Reddit follow once the post has survived
contact with readers. Same shape as `grade-a-trust`, which worked.

| Day | Channel | Draft | Posting |
|---|---|---|---|
| 0 | X thread | `-x.json` | Adapter (`getAdapter('x')`) |
| 0 | Discord `#announcements` | `-manual-channels.md` | Manual |
| 2 | Dev.to | `-devto.json` | Adapter (`getAdapter('devto')`) |
| 4 | Hacker News | `-manual-channels.md` | Manual — Brian submits, stays in comments |
| 4 | r/Angular | `-manual-channels.md` | Manual |
| 5 | LinkedIn | `-manual-channels.md` | Manual (no adapter) |
| 6–7 | Newsletter pitches | `-manual-channels.md` | Manual email |

Two days between Dev.to and HN is deliberate. If a technical claim in the post is wrong,
Dev.to comments will find it before the HN thread does, and correcting it there costs
nothing.

**Do not post HN and Reddit the same hour.** If HN takes off, that is where Brian needs
to be, and a Reddit thread going unanswered in parallel reads worse than posting it a
day later.

## Hacker News specifics

- Submit as a **link to the blog post**, not a Show HN. There is no interactive demo at
that URL, and Show HN sets an expectation this post does not meet.
- Title is neutral and technical. No version number in the title — it reads as a release
announcement and gets flagged.
- Brian posts the first comment himself immediately after submitting, and discloses that
he is the author in the first sentence.
- Best window: Tuesday–Thursday, 08:00–10:00 ET.
- If it does not catch in 90 minutes, leave it. Do not repost, do not ask for upvotes.

## r/Angular specifics

Read the subreddit rules before posting; self-promotion policy changes. The draft leads
with the practical question an Angular developer actually has and treats the release as
the answer, not the headline. Brian engages in comments; a drive-by post is worse than
no post.

## Assets

Render the social card before Day 0:

```bash
npx tsx --tsconfig marketing/assets/tsconfig.lib.json marketing/assets/scripts/preview.ts
```

**Pass `eyebrow` explicitly.** `marketing/assets/src/brand.ts:14` defaults to
`'Agent UI for Angular · MIT'`, which is retired positioning — the current line is
"The open-source thread-plane for agents." The website's copy contract does not scan
`marketing/`, so nothing catches this for you. Use:

```ts
await renderCard({
template: 'x-card',
eyebrow: 'Threadplane 0.1.0 · MIT',
title: 'The coffee in the hangar is free',
subtitle: 'Chat, durable threads, approvals, and generative UI for Angular. No paid tier.',
});
```

Card alt text (required by the X adapter, 1–1000 chars):

> Threadplane 0.1.0 announcement card: "The coffee in the hangar is free" over the
> subtitle "Chat, durable threads, approvals, and generative UI for Angular. No paid tier."

Two cards needed: `x-card` (1200×675) for the X thread, `og-card` (1200×630) for Dev.to.

## Guardrails

- **No competitor comparisons.** The `grade-a-trust` campaign named other frameworks
because it was reporting a public leaderboard. This campaign has no such excuse, and
a "vs them" frame invites a fight we do not need. The story is what we ship.
- **No absolute telemetry claims.** `apps/website/src/lib/public-copy-contract.ts` bars
"off by default", "we never collect", and similar. Say what is true and checkable:
no cloud service, no account, no activation.
- **Contractions are fine here.** `voice.md` measures the no-contraction rule from the
blog corpus. The shipped `grade-a-trust` social drafts use contractions freely, and
they read correctly. Blog register and social register are not the same register.
- **Name the weak spot.** Every draft in this campaign admits something — the version
history, the gaps, or the adoption number. The `grade-a-trust` campaign did this and
it was the most-quoted part. Do not let review sand it off.
- **"Free" needs its qualifier in the same breath.** Free software, paid support. Say
both, or the first one reads as bait.

## Measurement

Every link carries `utm_campaign=threadplane-0-1-0`, with `utm_source` per channel and
`utm_medium` of `social` (X, LinkedIn), `community` (HN, Reddit, Discord), `referral`
(newsletters), or `blog` (Dev.to).

Baseline before Day 0 so the delta is readable:

```bash
npm run posthog:report
```

Check at Day 7. What would make this a success:

- Referral sessions to `/blog/threadplane-0-1-0` from at least three distinct sources.
- Any movement on `/docs/chat/getting-started/try-without-a-backend`. That page is the
one that converts curiosity into an install, and it is linked from the post's table.
- GitHub stars. Adoption was the honest weak signal in June and it still is.

Do not treat X impressions as a result. `metrics()` on the X adapter is a stub until the
API tier is upgraded, so that number is not even collectable right now.

## Pre-flight checklist

- [ ] Blog post live at the anchor URL and rendering correctly
- [ ] Both cards rendered with an explicit `eyebrow`, eyeballed for layout
- [ ] `DRY_RUN=1` smoke for X and Dev.to adapters
- [ ] Every draft reviewed by Brian (`review_status` flipped off `awaiting-brian`)
- [ ] PostHog baseline captured
- [ ] r/Angular self-promotion rules re-read
- [ ] Brian available for the two hours after the HN submission
Loading
Loading