Skip to content

Add JavaScript span transform plugins - #28

Open
Stephen Belanger (Qard) wants to merge 8 commits into
mainfrom
t3code/explore-rquickjs-span-plugins
Open

Add JavaScript span transform plugins#28
Stephen Belanger (Qard) wants to merge 8 commits into
mainfrom
t3code/explore-rquickjs-span-plugins

Conversation

@Qard

@Qard Stephen Belanger (Qard) commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add ordered synchronous JavaScript span transforms powered by per-worker QuickJS runtimes
  • bridge spans and context directly with rquickjs-serde, using strict result decoding without intermediate JSON text
  • expose operation, source, session ID, and an environment snapshot captured once when each daemon worker processor is constructed
  • canonicalize plugin paths to absolute paths before validation and persistent enable storage
  • persist enabled plugins for ordinary sessions while keeping managed runs and import/attach plugin chains invocation-local
  • replay raw journal events through the resumed session's current plugin chain
  • fail closed when any plugin errors by withholding that span operation and retaining its raw journal entry for replay after repair
  • persist bounded, deduplicated raw QuickJS exceptions in private daemon state and surface them through bt trace doctor

Example

Create a synchronous ES module:

// tag-ci.mjs
export default function tagCi(span, context) {
  if (!context.env.CI) return span;

  return {
    ...span,
    tags: [...new Set([...(span.tags ?? []), "ci"])],
    metadata: {
      ...(span.metadata ?? {}),
      deployment: context.env.DEPLOYMENT_ENV ?? "unknown",
      trace_source: context.source,
    },
  };
}

Choose the scope when registering it:

# Persist an ordered global chain for ordinary Codex sessions.
bt trace enable codex --plugin ./redact.mjs --plugin ./tag-ci.mjs

# Only local.mjs runs for this managed invocation; enabled plugins are not merged.
bt trace run --plugin ./local.mjs codex -- "summarize this change"

# Only sanitize-history.mjs runs for this import; enabled plugins are not merged.
bt trace import codex SESSION_ID --plugin ./sanitize-history.mjs

Each function receives the previous plugin's returned span plus { operation, source, session_id, env }. Plugins may change span content but not span_id, root_span_id, or parent_span_ids.

Raw input events are journaled before transformation. On recovery, an ordinary session uses the current globally configured plugin chain, while an isolated managed session continues using its invocation-local chain. Import and attach are separate from journal recovery and use only their command-line plugins.

If any plugin throws, times out, returns a promise, or returns an invalid span, that span operation is discarded instead of being sent unredacted. The raw exception is stored locally in a bounded, deduplicated diagnostics registry and can be inspected with:

bt trace doctor codex

The failed plugin remains quarantined on that worker while its file is unchanged. Editing the plugin retries it; restarting the daemon then replays withheld journal operations through the repaired current plugin chain.

See the README examples for redaction, environment handling, chaining, replay, failure diagnostics, and security guidance.

Validation

  • cargo test --manifest-path bt-daemon/Cargo.toml --all-features --locked
  • cargo clippy --manifest-path bt-daemon/Cargo.toml --all-targets --all-features --locked -- -D warnings
  • cargo fmt --manifest-path bt-daemon/Cargo.toml -- --check
  • cargo metadata --manifest-path bt-daemon/Cargo.toml --locked --no-deps --format-version 1
  • make test
  • git diff --check

@Qard
Stephen Belanger (Qard) marked this pull request as ready for review August 21, 2026 15:17
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@realark Andrew Kent (realark) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

we should consider making the fail state configurable in the future. secret-scrubbing plugins that fail may wish to trigger a data drop instead, etc

Copy link
Copy Markdown
Collaborator Author

Good point. I had went for failing plugins just get skipped, since we don't really have a way to surface errors immediately, only logs. But in some cases a failure may actually be a critical thing that should block reporting. 🤔

@Qard
Stephen Belanger (Qard) force-pushed the t3code/explore-rquickjs-span-plugins branch from 3a20d75 to 41f9673 Compare September 3, 2026 16:48
@Qard

Copy link
Copy Markdown
Collaborator Author

Addressed the redaction-failure concern: plugin processing now fails closed for every plugin error, so the affected span operation is withheld rather than sent unredacted. The raw QuickJS exception is stored in a bounded, deduplicated local diagnostics registry and shown by bt trace doctor. A failed plugin stays quarantined while its file is unchanged; editing it retries processing, and daemon recovery replays withheld journal operations through the repaired current plugin chain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants