Skip to content

Logs and bug reports

This page shows what cora and cora-mcp can tell you about a problem, and where they write it. Reporting a problem says where to send a report.

npx cora info prints what a bug report needs, without launching anything:

  • which cora ran and why, and the cora-mcp release cora mcp would run;
  • Node.js, the operating system, the package manager, the CI provider, the coding agent that runs cora, and the one whose variables your environment carries, as an IDE’s terminal carries Claude Code’s;
  • the project’s config and its hash, and where its state and logs are;
  • where your user config is, whether it was read, and what it ignored;
  • the CORA service cora reaches, and its request timeout;
  • the Playwright packages and browsers cora would use, and axe-core’s version;
  • which of the environment variables cora reads are set.

Paste its output into the report, or attach npx cora info --json. Its reference entry says which values it prints.

cora info reports where the project’s Playwright expects its own Chromium, and the browsers in Playwright’s download directory. npx playwright install --list lists the browsers of every Playwright installation on the machine.

Checking the account, the scans and the fixes

Section titled “Checking the account, the scans and the fixes”

npx cora status shows whether your CORA account is valid, the project’s newest scans, and where each issue stands while CORA’s fixer works on it:

Account: valid, Acme, plan team, expires in 23 hours
Scans: 2 recent
20261006T170903123Z-a1b2c3d4: 1 target, 1 issue, from mcp, 2 minutes ago
20261006T170201123Z-k3j9x2ab: 11 targets (1 not scanned), 14 source files, 10 issues (1 needs review), from cli, 9 minutes ago
Fixes: 1 in progress, 2 not attempted, 1 done
in progress: rule axe/button-name, page http://localhost:5173/settings, element button.icon, last result still-failing, 2 attempts
not attempted: rule axe/color-contrast, page http://localhost:5173/, element a.footer-link
not attempted: rule axe/image-alt, page http://localhost:5173/, element img.hero
done: rule axe/label, page http://localhost:5173/signup, element input#email, last result fixed, 1 attempt

At a terminal, the scans and the fixes line up in columns under their headings where they fit its width, and a mark stands beside each verdict, such as ✓ beside valid, where the terminal draws one. With screenReader on, each scan and each fix stays one labeled line, as above.

  • Account is valid, with the organization, its plan and when the token expires, or not valid with the error that says why, such as account.missing before you sign in. It checks the account without renewing it, and exits 0 either way. A saved token that has expired reads as valid, token expired, renews on next use, since the next command that needs the account renews it.
  • Project reads not found when you run cora status outside a project. The scans and fixes it then lists are those in .cora/ in the folder you run it in (Scanning without a project).
  • Scans lists the five newest results files, from cora scan and from cora-mcp’s scans, each by its run ID, the name of its results file in .cora/runs/. Each gives the targets it covered, the source files it covered where its results cover some, the issues it found, what ran it and when, with the targets and the source files not scanned beside their counts. When .cora/runs/ holds more, a last line counts them, as in and 12 more in .cora/runs.
  • Fixes lists each issue a coding agent’s scans found, by where it stands:
    • in progress while verify_fix has not found it fixed;
    • not attempted before any fix of it was checked;
    • escalated once it was handed to a person after three attempts without a fix;
    • done once verify_fix found it fixed.

The fixes list empties as summarize_fixes reports the issues. A file this release cannot read, such as one another release wrote, is left out with a warning naming it: run file skipped or loop record skipped. A fix of an issue whose loop record is left out fails in verify_fix and summarize_fixes with mcp.loop-unreadable, which names the file to delete.

npx cora status --json prints whether the account is valid, the scans and the fixes as one JSON object, for scripts and status lines. Its versioned format, cora-status, is named by its format and version fields. cora status reads .cora/ wherever your stateDirectory moves it, in the project or outside one.

Each logging setting is a key of your user config, which applies to every command you run:

For example, to log at info, with a log file, in every project:

config.json
{
"log": { "level": "info", "file": true }
}

The global options set them for one command, such as --debug, which logs at debug and writes a log file. Where you cannot change the command, such as in CI, each one’s CORA_LOG_* variable sets it. Which value wins gives their order.

  • A command that writes a log file prints its path, Log: <path>, as its last line, after a blank line, whether it succeeded or failed. -q and --log-format json leave that line out, with the summary.
  • --log-file takes an optional path from the next argument. Write --log-file=<path>, or put --log-file last, when a target follows it.
  • CI debug mode logs at debug where no flag or variable sets the level, whatever your user config says. Re-running a GitHub Actions job with debug logging (RUNNER_DEBUG=1) turns it on, as does system.debug in Azure Pipelines.

Each line on stderr reads <time> <LEVEL> <message> key=value .... With --log-format json, each is a JSON object instead.

A log file holds every record at the chosen level as JSON Lines. Each line is one object, with @timestamp, level, message and the record’s fields under properties. Its first records say what may be in the file. The next describe the run: the cora, Node.js and Playwright versions, the browser, the config file and the log level, and for cora-mcp the agent’s client.

Log files live in .cora/logs/ in the project, or outside a project in the folder you run cora in, or wherever your stateDirectory moves .cora/. In a folder CORA cannot write, a log file you ask for is not written, and the command warns log file not opened, naming the file.

File Written by
cli-<time>-<pid>.log A cora command, when you ask for a log file
mcp-<time>-<pid>.log cora-mcp, when you ask for a log file
hooks-<session>.log The plugin’s hooks, always, one for each coding-agent session
crash-<time>-<pid>.log cora or cora-mcp, when it hits a bug

CORA keeps the newest files of each kind, and deletes older ones. log.filesKept sets how many. A log file at a path you name is never deleted.

When cora hits a bug, it writes a crash file next to the log files, and prints its path:

error[internal.unexpected]: cora hit an internal error
hint: Send this crash file to cora@vispero.com: `.cora/logs/crash-20261006T170501123Z-4242.log`

A crash file opens like a log file, with the latest of each record that describes the run:

  • cora started: the cora and Node.js versions, the platform, the project and the log level;
  • launch decided, for cora: which copy of cora ran the command, and why;
  • config loaded: the config file and its hash;
  • browser launched: the Playwright and browser versions;
  • version alignment, for cora-mcp: which release served the agent, and why;
  • client identified, for cora-mcp: the agent’s client.

Its last 200 other records follow, at debug whatever level it was printing, then the error. When cora-mcp hits a bug in a tool, it writes a crash file the same way, gives its path in the tool’s error, and keeps serving. Send the file with your report.

In a folder CORA cannot write, the crash file is not written, and the error says cora hit an internal error and could not write its crash file, or cora-mcp in place of cora. Report the command you ran, or what the agent was doing, instead.

CORA removes credentials before anything reaches stderr, a log file or a crash file:

  • passwords and tokens in URLs;
  • Authorization and cookie values;
  • tokens that look like JWTs or npm tokens;
  • the cookie and local-storage values of the storage-state file;
  • the values of environment variables whose names contain TOKEN, SECRET, PASSWORD or KEY, and where such a value is a file’s path, that path as CORA names it from the current directory or the project root;
  • the credentials in the URL of a proxy variable.

CORA removes the storage-state file’s values and the variables’ values only when they are 8 characters or more, since a shorter one would match ordinary text.

CORA finds a credential even where another tool’s terminal colors split it, such as an error a library printed in color, in its text or in the address of a terminal hyperlink; the text that held it is then written without its colors and links.

A results file removes less: the passwords in its URLs, and the URL parameters that only ever carry a credential, such as token. It holds each element’s markup as the engines report it, so a secret the page shows can reach it.

cora and cora-mcp read your user config as they start. A release ignores what it does not take in the file, rather than failing, and warns on stderr, naming the file:

  • user config setting ignored, for one key, with the key and what is wrong with it. That setting comes from the next source down.
  • user config ignored, for the whole file. Every setting then comes from the next source down.

What a release does not take says what each warning covers.

npx cora info shows the same in its User config section: the file’s path, whether it was read, and each thing it ignored, as in Ignored log.rotate: a key this release does not know. cora-mcp warns in its client’s log, which Seeing cora-mcp’s stderr shows how to read.

A process that hands over to another copy reads the file too, so a warning can show twice. A global cora hands over to the project’s, and cora-mcp to the project’s release.

DEBUG prints Playwright’s own diagnostics on stderr, and DEBUG_FILE writes them to a file instead:

Terminal window
DEBUG=pw:api,pw:browser npx cora scan

For cora-mcp, set DEBUG in the MCP entry’s env: pw:api,pw:browser for Playwright’s diagnostics, and pw:mcp:* for playwright-mcp’s.

cora and cora-mcp unset some of Playwright’s variables, such as PWDEBUG, since each would change what a scan finds. The environment variable reference lists them, and they still apply to your own Playwright tests.

cora-mcp logs on stderr, which the agent’s client keeps:

claude --debug=mcp writes MCP diagnostics, each server’s stderr included, to the session’s debug log, ~/.claude/debug/<session-id>.txt. --debug-file <path> writes the debug log to that path instead. Give the filter with =, as shown.

/mcp shows whether the server connected.

In any client, cora-mcp writes a log file of its own when your user config’s log.file, or CORA_LOG_FILE in its entry, asks for one, as More detail from cora-mcp shows.

At its default log.level, cora-mcp’s stderr shows which release serves the agent and why, the client, its settings, the config, the browser it launched, and a browser tool’s own error. A tool that fails is logged at warn, and a bug in cora-mcp at error, with its crash file. Each tool call is logged at debug.

cora-mcp takes no logging options. Set the logging settings in your user config, which reaches cora-mcp under every client and in every project:

config.json
{
"log": { "level": "debug", "file": true }
}

The plugin’s entries name no logging variable. Under Codex, one set in your shell never reaches the plugin’s cora-mcp, and Claude Code’s docs do not say whether it does. Your user config reaches cora-mcp under both. In an entry you write yourself, the settings’ variables in its env win over your user config for that entry:

.mcp.json
{
"mcpServers": {
"cora": {
"type": "stdio",
"command": "npx",
"args": [
"--yes",
"--prefer-offline=false",
"--fetch-retries=0",
"--fetch-timeout=3000",
"@vispero/cora-mcp@<version>"
],
"env": { "CORA_LOG_LEVEL": "debug", "CORA_LOG_FILE": "1" }
}
}
}

Either change applies when the client next starts the server. With a log file asked for, cora-mcp writes mcp-<time>-<pid>.log in the project’s .cora/logs/.

For an npx --no cora mcp entry, the same variables work. Or put cora’s own options before mcp, as in npx --no cora --log-level debug mcp: they pass on to the release it runs.