Missing tokens no longer abort the run. The credential is still created and
still attached to every node that needs it, holding a placeholder — so the
workflows open without a missing-credential warning and nothing is left
half-wired. They just cannot run until a real token is supplied.
The placeholder is labelled in both places someone will look: the credential
name becomes "Anthropic (seed, fake key)", which is what shows in the
credential list and on every node, and the stored key is
SEEDED-FAKE-KEY-not-a-real-credential, so a 401 in a log explains itself rather
than raising a question about which key was used. The name is resolved once and
used for the row, the cached name on each node, and the report, so those three
cannot disagree.
The report ends with what to do about it: which token each placeholder needs,
where to generate it, and every place it can be set, each marked exists or
create it. Re-running with the token set replaces the credential in place and
keeps its id, so every node keeps pointing at it and the label drops away —
verified by seeding placeholders and then re-seeding with real tokens.
SEED_PLACEHOLDER_CREDENTIALS=1 forces placeholders even where a real token is
available, for producing a database with no real keys in it or for seeing the
estate as it looks before anything is configured.
`pnpm inspect:activity` serves every column of `activity_event` on
127.0.0.1:5699 — paginated, sortable on any column, with a free-text filter
that also searches the JSON `data` column, so a run id or a failing node name
finds its entry without knowing which field holds it. Category and action get
their own dropdowns, listing what is actually in the table.
Standalone rather than a view in the editor UI, on purpose. An in-app page
would need a route, a store, an API client, a scope-gated endpoint, i18n
strings and tests — a lot of product surface for a table you want to eyeball
while working on it. This is one file, no build step and no dependency, and it
reads the database directly so what you see is what is stored.
Read-only in three ways that matter: the connection is opened with readOnly, so
a write is rejected by SQLite rather than by convention; every query is a
SELECT; and the sort column comes from an allowlist, because a column name
cannot be a bound parameter. Verified — a sort of `1; DROP TABLE
activity_event` falls back to id and leaves the table intact.
Bound to 127.0.0.1 only, and unauthenticated by design: it is a debug surface,
and the whole table including who did what in which project is served to
anything that can reach the port. Confirmed unreachable on the LAN address.
Verified in a browser against a seeded database: filters, header sorting, page
size and paging all drive correctly, the free-text search finds both failing
runs by their failing node name, and the console is clean.
`pnpm seed:account` builds n8n-core and runs the seed in one command, so the
build prerequisite stops being something you have to know.
Tokens now resolve from the environment or from a dotenv file this repo already
uses for local secrets — packages/cli/.env, packages/@n8n/instance-ai/.env, or a
root .env, in that order, with the shell always winning. Only the two token
variables are taken from those files, so nothing else in them leaks into the
process. A missing token is named with the credential it is for, where to
generate it, and every place it can be set, each marked exists or create it. The
run report says which source each token came from and how long it is, never its
value.
Also puts it where an agent will actually look: a section in the root AGENTS.md
saying what the seed contains, when to reach for it, and how it differs from
seedInstance.mjs. An empty instance is a bad place to test anything that reasons
about a user's work, and until now nothing in the docs an agent loads by default
said a seed existed.