Skip to main content
Artifacta stores transcripts as ordinary, opaque artifacts. Transcript sugar fills the conventional metadata.type="transcript" tag and the application/x-ndjson content type without adding a transcript resource, endpoint, or server-side schema. Start with the checked-in recommended NDJSON example, or store your agent’s existing transcript format.

Use one session for the transcript and its outputs

Give the transcript and every artifact produced during a run the same session ID. You can then list the whole run or filter it to the transcript alone.
--transcript defaults the upload to content_type=application/x-ndjson and adds metadata.type=transcript. It does not change output, errors, TTL, sealing, deduplication, idempotency, or upload limits.

Explicit values take precedence

Write precedence is independent for the two defaults:
  1. An explicit content type always wins; otherwise a true transcript flag supplies application/x-ndjson before filename MIME guessing.
  2. The presence of an explicit metadata type key always wins, including type=""; otherwise a true transcript flag supplies type="transcript".
  3. When the flag is omitted or false, existing MIME guessing and metadata behavior remain unchanged.
On list calls, an explicit metadata type filter wins, including an empty value. Otherwise a true transcript flag adds exactly one metadata.type=transcript filter. Other metadata is preserved in every case.

Python SDK

transcript is a keyword-only boolean on the existing push() and list() methods. Their public signatures are:
Use either a path or the existing content plus filename form:

MCP tools

Both the TypeScript and Python MCP servers expose the same optional boolean on the existing tools. store_artifact remains a writeIdempotent tool, and list_artifacts remains a safe tool.
store_artifact arguments
list_artifacts arguments
The write flag works with both MCP content and path uploads. The same explicit-value precedence above applies to content_type and metadata.type; list calls preserve an explicit metadata.type filter.

Call the REST API directly

The REST API is unchanged. API-direct callers express the convention with existing metadata, content_type, and metadata-filter parameters. The API does not infer NDJSON from metadata.type alone, so send the desired content type explicitly.

Multipart upload

Multipart metadata is a JSON string. file and content_type are separate existing form fields.

JSON-body upload

JSON uploads carry base64 content, content_encoding="base64", a filename, object metadata, and an explicit content type.

List transcripts

Use the existing metadata query and URL-encode the query string:
There is no REST transcript field or query parameter on create or list requests.

Capture Claude Code sessions automatically

This recipe uses Claude Code’s client-side SessionEnd hook to invoke the same Artifacta CLI push shown above. Artifacta does not run a listener or provide a separate capture service.
In Claude Code with the Artifacta plugin: install with /plugin marketplace add SagaPeak/artifacta-mcp then /plugin install artifacta@artifacta, and ask in natural language — for example, “use artifacta to upload this session’s transcript”. The plugin’s capture-transcript skill locates and verifies the live session transcript, pushes a snapshot, and can offer to set up this hook for you.

Prerequisites

  • Install and authenticate the artifacta CLI, and ensure artifacta is on PATH.
  • Install jq and ensure it is on PATH.
  • The documented hook expects JSON on stdin with session_id, transcript_path, and reason. It reads the first two fields; transcript_path must name an existing file.
Add this hook to ~/.claude/settings.json:
Create ~/.claude/hooks/push-transcript.sh with these exact contents:
Make the script executable:
Malformed JSON causes jq to fail. Missing, null, or empty required fields and a nonexistent transcript file also fail validation. Any non-zero Artifacta CLI exit propagates as a non-zero Claude Code hook failure. Input validation and the Artifacta push still fail hard: there are no retries and no swallowed push errors. Model extraction alone is best-effort; if it fails or finds no main-loop model, the script pushes the transcript without model metadata rather than losing the upload.
SessionEnd, its lifecycle, and the session_id, transcript_path, and reason stdin fields are an external contract owned by Anthropic. Artifacta does not pin or abstract that contract. Re-check Anthropic’s hook documentation after upgrading Claude Code.

Model capture

The hook script above also records which model produced the session, straight from the transcript itself:
  • metadata.model — the last main-loop assistant model in the transcript. Sidechain (subagent) entries and synthetic placeholders are excluded via the transcript’s isSidechain marker, so a session that dispatched subagents on a different model still attributes to the orchestrating model — the model that directed the work and decided what got stored.
  • metadata.model_source=transcript — marks the value as machine-captured. Absence of model_source means the model was declared by the caller.
  • metadata.models_used — every distinct model observed in the transcript, comma-separated (e.g. claude-fable-5,claude-sonnet-5), including subagent sidechains.
Artifacta records the model automatically from the agent runtime’s own session log and freezes it at store time — a captured producer claim, not a cryptographic attestation. Two honest limits: session-level capture approximates per-artifact authorship — the transcript proves which models participated in the session, not which one emitted a specific artifact’s bytes; and subagents spawned as separate sessions don’t appear in the main transcript, so models_used is “models observed”, never exhaustive. For pushes outside the hook, declare the model yourself: artifacta push report.pdf --model claude-fable-5 (shorthand for --meta model=), or export ARTIFACTA_MODEL once in a wrapper script — explicit flags always beat the environment. If a wholly-delegated subagent authored the artifact, pass that subagent’s model explicitly. Published pages render metadata.model in the page receipt automatically.

Verify a captured transcript

An unfiltered session list should include both the transcript and the artifacts produced by the run. The transcript-filtered list should include only artifacts whose explicit metadata type is transcript. For a later native Claude Code lifecycle check, use the repository’s reproducible SessionEnd operator validation. That optional follow-up is not a PR blocker: automated exact-hook tests and live execution with canonical synthetic stdin already passed.

Security: audit before you push

Artifacta does not automatically scan, redact, or block secrets in transcript uploads. Callers are responsible for reviewing and redacting transcript content before storage. For an optional source-checkout audit, run the repository’s existing scanner against a directory before pushing it:
The scanner exits 0 when clean, 1 when it finds credential-shaped content, and 2 for a usage error. It reports locations and pattern names without echoing matched values. The repeatable --allow <string> option can suppress a known benign match. This user-run audit is optional, is available only from a source checkout, and is not an Artifacta push gate; you may wire it into your own pre-push hook if desired.

Codex plugin

Artifacta plugin 1.1.0 supports verified transcript capture in Codex. Install and authenticate it with the Codex plugin guide, then start a new thread so Codex loads the plugin’s skills and hooks. For an immediate snapshot, ask:
“Use Artifacta to capture this Codex session’s transcript.”
The capture-transcript skill searches Codex’s rollout files for a distinctive phrase from the current conversation and refuses to continue unless it identifies exactly one regular file. It copies that live rollout to a private snapshot, uploads the snapshot through Artifacta MCP store_artifact, and removes the private copy after a successful upload. Codex transcript capture never invokes the local Artifacta CLI or sends a local filesystem path to the hosted MCP server. For one capture at the current thread’s next Stop, include the explicit flag:
“Use Artifacta to capture this Codex session’s transcript —automatic.”
--automatic arms one unredacted snapshot for this thread only. It does not enable every-turn capture, future-thread capture, or a background uploader. Open /hooks, review the bundled Artifacta hook, and trust its current definition; Codex skips untrusted non-managed hooks. An immediate mid-turn snapshot may not include the request that triggered capture or the assistant response reporting its result. Retrieve captured records with list_artifacts using the returned session ID and transcript=true.
Codex snapshots are uploaded without redaction and can include prompts, tool arguments, tool results, credentials, and other sensitive text. Review the session before requesting capture.

Limitations and hard exclusions

  • Transcript payloads remain opaque bytes. NDJSON is recommended, not a mandatory schema.
  • There is no incremental, streaming, chunked, or per-turn upload/reassembly behavior.
  • There are no dedicated push_transcript, get_transcript, pull-transcript, or MCP get_transcript APIs or tools.
  • There is no server-side agent-session detection or continuous capture mechanism. The Claude Code and Codex plugin skills perform verified client-side capture.
  • There is no server-side enforcement of the metadata.type convention and no transcript web viewer.
  • Existing artifact limits, retention/TTL choices, session seals, and errors apply unchanged.