Roadmap Product site

Overview

Core concepts

Red Pen is one idea wearing five coats. A note is the same object whether you left it in WordPress, an Express app, a static page, a Blender scene, or Ableton. That shared model is exactly what lets the Hub roll every project into one board. This page is the vocabulary; the surface pages show how each platform realizes it.

Spec-driven, not shared code The family has a single written contract (the family spec). Each surface implements it in its own native idiom: PHP on WordPress, middleware in Express, a browser script for static sites, a Python add-on in Blender, a TypeScript extension in Ableton. Nothing is shared as code; the model is what is shared. When a capability changes, the spec changes first, then each port catches up. That is why some features below are fully present on one surface and still planned on another. The Surface matrix is the per-feature answer for which surface has what today, and the Roadmap covers what is next.

The three principles

Everything in Red Pen follows from the four commitments on the Home page. Restated here because they decide how every field below behaves:

The note model

A note is the core object. Every surface stores it differently (a WordPress post, a line in .redpen/notes.jsonl, a localStorage entry, a JSON sidecar beside the .blend, or an external notes.json for Live) but the shape is the contract. These are the fields:

FieldTypeMeaningExample
idstringPort-assigned, opaque, stable for the life of the note. How every other tool (and the Hub) addresses it.n_mqnh6jofiegeo
bodystringThe note text. Plain text, stored raw, always rendered escaped.Header logo is 4px too low
typeenumThe kind of note. See Note types. Stored as the enum key.bug
priorityenumlow / normal / high. See Priorities.high
severityenum, optionalThe impact axis, distinct from priority (which is scheduling). blocker / critical / major / minor / trivial. Empty by default. See Severities.critical
statusenumopen / in_progress / resolved. See Workflow.open
contextstringWhat the note is scoped to, so a surface can show "notes here". On the web this is the page path; see Context./pricing
urlstringA human-resolvable location for the note, usually the page URL. Optional. The Hub uses it for "jump to source".http://localhost/pricing
anchorobject or nullThe element or position the note is pinned to, or null for a context-level note. See Anchors.{ sel: "#logo", x: 0.5, y: 0.5 }
assigneestringWho owns the note. A WordPress user id on WP, a free-text handle elsewhere. Optional. See Assignee.lincoln
agentstringAn AI agent slug when the note is delegated to an agent rather than a person. Empty means a human note. See Assignee & agent.claude
codeScopestringAn optional file or symbol reference attached to an agent note, so the agent knows where to look.src/header.php
repliesarrayA flat, one-level thread: [{ author?, body, createdAt }]. See Replies.[{ body: "Fixed in r482", ... }]
screenshotstring or nullA reference to an attached region capture, or null. See Screenshots.shot_4f2a.webp
createdAtstringISO 8601 timestamp of when the note was created.2026-06-21T07:38:51Z
editedAtstringISO 8601 timestamp of the last field edit, where a surface records it (for example Express stamps it on a body/type/priority edit). Optional.2026-06-21T08:02:10Z
resolvedAtstring, optionalISO 8601 timestamp stamped when a note is resolved, and cleared again on reopen. Feeds the Hub's Resolved column.2026-07-03T15:02:11Z
resolvedBystring, optionalWho resolved the note, where the surface has identity (WordPress records the user's display name; a Hub-originated resolve is left unattributed).Lincoln
statusAtstringISO 8601 UTC, stamped every time the status moves in either direction. This is the cross-surface contract field: the Hub compares it with its own board-side override to decide who acted last, and a surface that omits it gets its changes force-reverted by one stale click. Every surface reports it today.2026-08-04T11:20:03Z
authorstring, optionalWho wrote the note, on surfaces that have a name to use. Never guessed, and blank until the surface has one.Lincoln
typeLabelstring, optionalThe display label for a custom ct_ type, sent alongside typeColor so the Hub renders the label you chose instead of the raw slug.Copy fix

Surfaces may carry a few extra platform-only fields (WordPress, for instance, stores a structured context key and template metadata), but the fields above are the portable core that the Hub normalizes against.

Note types

Every note has a type. There are four built-in types; the stored value is the enum key, and the label shown in the UI may differ (and may be localized):

Stored keyShown asUse it for
noteNoteA neutral observation or reminder.
suggestionIdeaA proposed change or improvement.
bugProblemSomething broken that needs fixing.
questionQuestionSomething to clarify or decide.

Custom note types are part of the free core: you can define your own types, each with an optional colour flag, and they merge into every type dropdown and render their colour on the note. They ship on WordPress (site-wide, defined as Label|#hexcolor lines in Display settings, stored with a ct_ key prefix) and on the static drop-in (per browser, label and colour, defined in Settings). The Hub renders a custom type's own label and colour when a surface sends them, and humanizes the slug when it does not. Express, Blender and Ableton have the four built-ins only. See the Surface matrix for the current grid and the Roadmap for what is next.

Priorities

A note carries one of three priorities: low, normal (the default, sometimes surfaced as "medium"), and high. Priority drives sorting and at-a-glance triage. High priority is rendered in the brand red (#D32F2F) across the surfaces and on the Hub board, so the things that matter stand out without you reading a word.

Severities

Severity is a second, optional axis that answers a different question than priority. Priority is about scheduling: when should this be done. Severity is about impact: how bad is it if it stays. The two are orthogonal: a low-priority, high-severity crash is a real thing (it will hurt badly, but not today), and so is a high-priority, low-severity typo on the launch page. Severity is unset by default and shown only when you deliberately choose one, so it never adds noise to notes that do not need it. There are five keys:

Stored keyShown asUse it for
blockerBlockerStops the work or the release entirely.
criticalCriticalSevere impact: data loss, a broken core flow.
majorMajorA significant problem with a workaround.
minorMinorA small, contained issue.
trivialTrivialCosmetic or nice-to-have.

Only WordPress authors severity today (set in the note form, dev-only). The Hub board and the CSV export display it, and the other surfaces can adopt it later. The field is part of the shared model regardless of which surface writes it.

Status and workflow

Notes move through a small, explicit workflow rather than just existing as sticky notes:

StatusMeaningMarker
openLogged, not started. Keeps its pin on the page.Brand red
in_progressBeing worked on. Keeps its pin.Amber
resolvedDone. Drops out of the active list and its pin is removed.(hidden from active)

Resolving a note clears it from the working view; reopening brings it back. The overlay's panel is organized into Open / (In Progress) / Resolved tabs with live counts so you always know what is left. Resolve also offers an undo in case you closed the wrong one.

A resolve now also records when it happened (a resolvedAt timestamp, cleared again on reopen) and, on surfaces that have identity, who did it (resolvedBy; WordPress stores the user's display name). The Hub board surfaces both as its Created and Resolved columns, so you can see and sort by when each note opened and closed.

Surface difference The full three-state model (Open / In Progress / Resolved) is shipped on every surface (WordPress, the static drop-in, Blender, Ableton, and, since v0.3.0, the Express middleware), and all three are settable from the Hub board too. One naming note: the spec's middle status is in_progress, while the Hub and some surfaces store progress. Express and the static drop-in both accept every spelling on the way in and emit in_progress. The Hub understands all three states regardless, treating anything that is not in-progress or resolved as open.

Context and scoping

Every note belongs to a context, which is how a surface answers "what notes are on this page / this thing?":

Anchors and pinning

A note can be pinned to a specific spot, or left at the context level (anchor: null). Pinning is what turns "the button near the header" into a note that points at the exact button.

On the web surfaces, an anchor is { sel, x, y }: a CSS-selector path to the element (it prefers an #id, otherwise builds an nth-of-type chain), plus a relative position x / y from 0 to 1 within the element's box. To create one you click Pin, then click the element. A numbered red marker then renders over that element and repositions as the page scrolls or resizes; Locate on a note scrolls to and briefly flashes its element.

In Ableton, an anchor is platform-specific: a beat range from an arrangement selection, or the identity of a clip, track, or scene. Locating there is deliberately weaker than on the web: Live 12's Extensions API exposes no way to select a clip, scroll the view, or switch between Session and Arrangement, so the button is called Flash and it blinks the clip's colour rather than jumping to it. For time anchors, Red Pen writes a native Live locator named RP: ... onto the timeline, and that visible locator IS the locate feature. See the Ableton surface page for what that writes into your Set.

Threaded replies

Each note can carry a flat, single-level thread of replies, shaped [{ author?, body, createdAt }]. You add a reply from the overlay, and the thread shows on the note and in the repository. It is enough to capture a back-and-forth ("is this still happening?" / "fixed in the last deploy") without turning Red Pen into a full discussion tool.

Replies ship on WordPress, Express, the static drop-in and Ableton. The Blender add-on does not have them yet, and the Hub shows a reply count without a thread view or a way to post.

Screenshots

A note can carry an optional region capture: drag a box around any area of the page and the snip is attached to the note (captured with html2canvas, stored as a small WebP or data URL). The capture shows on the note and in the repository, and is served gated like everything else (a capability check plus nonce on WordPress).

Surface difference Region capture ships on WordPress only. Blender has the equivalent for its medium (a viewport snapshot saved beside the .blend and shown on the note) and pushes it to the Hub, which renders it on the board. Express declares screenshots: false in its own capability block and the static drop-in has no capture; both are tracked on the Roadmap (Express v0.4.0). There is no image to capture in a DAW, so Ableton is not a candidate. Audio snips are the analogue there, and they are not built. The Surface matrix has the current grid.

Assignee and agent

Two related fields record who a note is for, and they are how Red Pen distinguishes manual work from automated work:

An agent consumes its queue locally, with no keys and nothing leaving the machine, in one of two ways: a filtered query (for example GET /notes?agent=claude) or an auto-maintained agent-<slug>.json brief file it reads off disk. In practice "check for red pens" means: pull the open notes (optionally one agent's), fix them, and mark each resolved.

Surface difference The assignee and agent model is implemented on WordPress only. Express, the static drop-in, Blender and Ableton do not have it. It is in the family spec, not in those ports. The Hub displays and exports an assignee but cannot set one; making it settable from the board through the write-back path is planned. Until then, the Hub shows whatever assignee data a connected WordPress source already carries. See the Surface matrix and the Roadmap.

Export and import

No export is behind a payment anywhere, and none is planned to be. Export is not uniform either, and three of the six have no one-click export at all. The state today:

SurfaceGetting notes out today
Static drop-inFull JSON export and import from the All-notes board: replace-all or merge by id. The only surface with a complete round trip.
WordPressCSV export from the repository, honouring the active filters, plus the printable client report. No JSON export and no import.
AbletonJSON and CSV, written to the store folder. The CSV drops replies, status timestamps and the anchor, so it does not round-trip. Import reads a fixed filename from that folder, because Live's sandbox blocks a file picker.
ExpressNo export command. The store is plain text in your repo (.redpen/notes.jsonl and its notes.json snapshot), so taking a copy is copying a file.
BlenderNo export operator. The sidecar beside the .blend is already JSON.
HubMarkdown digest and CSV of the current view. No JSON export button; the aggregate is on the local API.

The commitment underneath is narrower than "always portable": your notes are never in a format only we can read, and never behind a payment. Every store above is plain text or a standard WordPress post type on your own disk. Where a one-click export is missing, that is unbuilt work. See the Surface matrix for the grid and the Roadmap for the plan to bring Markdown export down from the Hub to every surface.

How the surfaces relate

Because all five surfaces speak the same note model, a companion piece can aggregate them: the Red Pen Hub reads each surface's store through a small adapter, normalizes every note to the fields above, and shows them on one board, tagging each with its project and surface. The Hub is also where the model's two-way side lives today: you can resolve or reopen a note from the board and it writes back to the real source. Everything the Hub does rests on this shared vocabulary.

From here, head to the page for the surface you are using: