/Context

Foundation setup

Set up your organization’s context

Manifesto, positioning, identity, ranking targets and competitors: what your topic map, GEO matching and writing all read. Do this before your main blog (/docs/onboard/collection). Follow the steps or hand the prompt to your agent.

Not one-time. Re-run ingest_context whenever something changes.

Before you start

  • 1Create an API key (Settings → API keys → Create key). Send it in the x-integrations-key header, not Authorization: Bearer.
  • 2Gather what you have: notes, an about page, a deck or press links. Nothing? Step 2 below covers it.
Agent setup promptPaste into Claude, or any agent with web + API access.
You are setting up a Letterstory organization's context: what it IS, what it should write about, what it should rank/be cited for, and who it competes with. This feeds every downstream system — the topic map, GEO mention-matching, and on-brand generation all read this — so treat it as foundational setup, not optional polish. Work through the phases in order; a from-scratch org should not skip to collection/blog setup at /docs/onboard/collection before this is done.

Connect first:
- This guide is for an EXISTING Letterstory customer. If the user has somehow not signed up yet, that happens at https://app.letterstory.com/crossing/letter with a work email and is theirs to do in a browser, not something you can do over the API.
- Ask the user for their Letterstory API key if you don't have one (Letterstory dashboard -> Settings -> API keys -> Create key). In the Create key dialog, pick the "Onboarding + publishing agent" preset - a key created with the defaults can only read published posts, and almost every call below would fail on a missing capability. Keys are not issued over the API, so this step also happens in the browser. Send it as an x-integrations-key header (Authorization: Bearer is for OAuth access tokens, a different credential type - it will reject a plain API key with 401).
- Get the tool schemas by POSTing a JSON-RPC tools/list request to https://app.letterstory.com/api/mcp - plain HTTP is fine, you do not need an MCP client. That is the ONLY place per-tool parameters live. https://app.letterstory.com/api/openapi describes the REST dispatcher (one generic tools/{name} path with an untyped body) and carries no per-tool schema, so it cannot tell you what a tool takes. Tool names below are anchors, not the full signature - look up the current schema before calling anything.
- Call get_onboarding_plan first. Its context step is this guide: done means positioning is already set (then this is a refinement, not first-time setup), ready means start here, blocked on domain_set means call set_company_info with the public site domain before anything else. The same plan shows what the Planner and phantom steps are waiting on, which is usually this step.
- Call get_organization to see the current domain/name/description. If the org has real material to draw from (a live site, notes, docs), go to Phase 1. If it's a genuine blank slate with nothing to feed in, skip to Phase 2.
- THE ENGINE MAY HAVE DONE THIS ALREADY. onboard_collection reads the org's public site during its first stage and writes positioning, identity, voice and visuals from it - a measured 27 fields on a real run. So if the plan's collection step is done, positioning is the engine's inference from the site, not a blank slate: call get_positioning FIRST and treat this guide as correcting what it got wrong, not as filling in an empty org. Re-ingesting the same site to "set up" an org that onboarding already read wastes a call and can overwrite a human's correction with the same machine guess.

Phase 1 - Feed what you know (the normal path)
- Ask the user for anything they have: free-text notes about the company, links (about page, pitch deck, product docs, press), and whether to include a fresh read of their own website.
- Call ingest_context with whatever combination of text / links / include_website you gathered. This does NOT persist anything - it returns a reviewable proposal: a list of changes across positioning, competitors, identity, voice/branding and visuals, each with a stable id, a before/after, and a rationale.
- Walk the user through the proposal, especially identity and positioning changes since those are the most consequential (identity in particular decides what counts as "this company" being cited elsewhere - get it wrong and GEO mention-matching gets it wrong everywhere downstream). Ask which change ids to accept; don't auto-accept everything without at least surfacing what's about to change.
- Call apply_context with the ingestion_id and the accepted change ids. Only accepted changes are written - positioning is versioned, competitors are only ever added (never silently removed), identity and visuals are merged rather than replaced.
- Verify what you can, and be honest about what you cannot. get_positioning reads back priority_topics/stances/avoid_topics; list_competitors reads back competitors; the MANIFESTO lands on get_organization's description field, NOT on get_positioning, which has no such field. Identity (what the company is, what it is not, its descriptors, its one-liner and its default framing) has no read-back tool at all right now - get_brand_context returns null unless import_brand_context populated it, and its own description says the judgement half is not there. So do not claim identity was applied because apply_context returned ok; say plainly that it reported success and cannot currently be read back.
- Important: there is no standalone "set identity" tool. is / is-not claims, descriptors, the one-liner, and default framing - the org's Identity - can ONLY be set or corrected through ingest_context -> apply_context. If the user wants to fix just one identity fact later, run ingest_context again with a short note describing the correction; don't go looking for a more direct tool that doesn't exist.

Phase 2 - No existing material? Bootstrap from just a domain
- If there was nothing to feed into Phase 1 (no notes, no links, no meaningful existing site), call suggest_onboarding instead (optionally passing domain, else it uses the org's stored one). It drafts an org description, editorial positioning (priority_topics / stances / avoid_topics), and evidence-based ranking targets in a single read-only call - nothing is persisted by this call itself.
- Apply the draft explicitly and tell the user you're doing so: set_company_info (manifesto: the drafted description), set_positioning (the drafted priority_topics/stances/avoid_topics), and add_ranking_target once per suggested target you and the user want to keep.
- Verify: get_positioning and list_ranking_targets show what you actually applied, not just what suggest_onboarding drafted.

Phase 3 - Ranking targets (if not already fully covered by Phase 1 or 2)
- suggest_ranking_targets any time for more evidence-based candidates - it combines positioning stances, what the client's own site already ranks for, and what AI assistants already name them for.
- add_ranking_target for each one worth tracking. There's an active-target cap - if you hit it, the error message names the current limit; retire a weaker target with update_ranking_target before adding past it rather than treating the cap as a hard stop.
- Verify: list_ranking_targets.

Phase 4 - Competitors (if not already fully covered by Phase 1 or 2)
- guess_geo_competitors for AI-suggested competitor domains. It returns configured: false with an empty list when no competitor-search provider is set up for this deployment - tell the user that plainly rather than reporting "no competitors found."
- add_competitor for each one to track. A company can't be added as its own competitor (the call is rejected) - if that happens, don't retry with a slightly different spelling of the same domain, it's a real guard. The domain is scraped in the background on first add so its topics feed positioning context.
- Verify: list_competitors.

Guardrails:
- This is customer-facing self-serve context setup. It is not the staff-run "phantom"/hosted-storefront tooling - don't reach for plan_phantom, set_phantom_config, onboard_domain, create_phantom, etc. here.
- Re-running ingest_context later is the correct, intended way to correct what the system believes about this org - it's not a one-time setup step you graduate out of.
- Once this is in reasonable shape, move to https://app.letterstory.com/docs/onboard/collection to create or configure the main blog collection - it reads positioning to build its topic map, so sequencing matters.
- If something in this flow doesn't match what tools/list or /api/openapi actually shows, trust the live schema over this prompt and tell the user what changed.

The four pieces

1

Feed what you know

Give the agent notes, links or your website. ingest_context returns a proposal (nothing saved) for positioning, competitors, identity, voice and visuals, each with a before/after and a reason. Check identity closely: it decides which mentions count as you. apply_context saves only what you accept.

  • ingest_context
  • apply_context
  • get_positioning
  • list_competitors
  • get_brand_context
Verify:get_positioning, list_competitors, and get_brand_context / get_org_branding show the accepted changes, not just the proposal.
2

Nothing to feed in? Bootstrap from a domain

Starting from nothing? suggest_onboarding drafts a description, positioning and ranking targets from your domain. It saves nothing; apply what you want with set_company_info, set_positioning and add_ranking_target.

  • suggest_onboarding
  • set_company_info
  • set_positioning
  • add_ranking_target
Verify:get_positioning and list_ranking_targets show what you applied.
3

Ranking goals

suggest_ranking_targets drafts candidates from your positioning, rankings and AI mentions. add_ranking_target tracks one. Active targets are capped; retire weak ones with update_ranking_target.

  • suggest_ranking_targets
  • add_ranking_target
  • update_ranking_target
  • list_ranking_targets
Verify:list_ranking_targets shows the targets you added.
4

Competitors

guess_geo_competitors suggests domains from your positioning (configured: false means no search provider is set up). add_competitor tracks one and scrapes it in the background. You can't add your own domain.

  • guess_geo_competitors
  • add_competitor
  • list_competitors
Verify:list_competitors shows what you added.

Full parameters and curl for every tool: /docs/api.