Tarsk Plugins

Audit Logging

Validates that code uses the standardized Tarsk logger with proper log levels and dot-notated event names. Use when adding or updating logging, reviewing code changes, or auditing existing files for logging compliance.

Source: /skills/audit-logging/SKILL.md

Audit Logging

Validate that all logging in Tarsk uses the standardized shared logger.

The Standard

Every log statement in Tarsk must use createLogger from @tarsk/shared.

import { createLogger } from "@tarsk/shared";

const log = createLogger("domain.action");

log.debug("Detailed diagnostic info", { key: "value" });
log.info("Normal operation event", { key: "value" });
log.warn("Degraded but recoverable", { key: "value" });
log.error("Operation failed", error);

No raw console.log, console.error, console.warn, or console.debug calls outside of the logger implementation itself.

Log Event Naming

Event names use lowercase dot-notation. The first segment is the domain; subsequent segments narrow the scope.

Format: domain.action or domain.subdomain.action

Examples:

  • agent.executor -- AI agent execution
  • agent.subagent -- Sub-agent spawning
  • chat.post -- Chat message posting
  • chat.stop -- Chat generation stop
  • chat.media -- Media loading in chat
  • git.push -- Git push operations
  • git.create-pr -- Pull request creation
  • git.sync-branch -- Branch synchronization
  • gitops.timing -- Git operations timing
  • gitops.subprocess -- Subprocess timing
  • gitops.ttl-cache -- TTL cache operations
  • gitops.api -- Frontend git API calls
  • mcp.connection -- MCP server connections
  • mcp.tools -- MCP tool loading
  • db.migration -- Database migrations
  • routes -- HTTP route error logging
  • logs.api -- Log forwarding endpoint
  • voice.stt -- Speech-to-text
  • voice.tts -- Text-to-speech
  • voice.vosk-cache -- Vosk model caching
  • models.catalog -- Model catalog operations
  • models.info -- Model info fetching
  • projects.open -- Opening projects
  • agents.manager -- Agent file management
  • image.generate -- Image generation
  • image.save -- Image saving
  • skills.frontmatter -- Skill file parsing
  • store -- Frontend state management
  • browser.tool -- Browser tool operations

Rules:

  1. All lowercase, no spaces.
  2. Segments separated by dots.
  3. No bracket prefixes ([tag]), no emoji, no decorative characters.
  4. Keep segment names short but descriptive (2-4 words max per segment).
  5. Reuse existing domain names when adding logging to an existing subsystem.

Log Levels

Level When to use Survives production?
DEBUG Timing data, cache hits/misses, request/response payloads, internal state transitions. Disabled in production. No (set to WARN in production)
INFO Successful operations, state changes, user actions, configuration loaded. No (set to WARN in production)
WARN Degraded but recoverable conditions, fallback paths taken, deprecated API usage, validation failures. Yes
ERROR Operation failures, uncaught exceptions, data corruption, external service failures. Yes

Production behavior: The CLI entrypoint sets LogLevel.WARN unless --debug is passed. This means DEBUG and INFO calls are silent in production. Only WARN and ERROR produce output.

Rules:

  1. Never use ERROR for expected conditions (e.g., validation failures that return 400).
  2. Never use WARN for normal operational messages -- use INFO instead.
  3. Use DEBUG for anything that would be noisy in development (timing, cache state, event payloads).
  4. Include structured data as the second argument rather than interpolating into the message string.

Message Format

Good:

log.info("Agent prompt completed", { model, provider, duration: ms });
log.error("Failed to save conversation", error);
log.debug("Cache hit", { key, ms });

Bad:

console.log(`[ai] Agent prompt completed successfully for ${model} from ${provider} in ${ms}ms`);
console.error("[chat-media] Failed to load media", details);
console.warn("[MCP] Connected to " + serverName);

Rules:

  1. Message is a short, human-readable sentence. No prefix tags, no emoji.
  2. Structured data goes in the second argument as an object.
  3. Error objects pass directly as the data argument -- the logger serializes them safely.
  4. Do not stringify data into the message string.

Import Path

CLI (backend):

import { createLogger } from "@tarsk/shared";

App (frontend):

import { createLogger } from "@tarsk/shared";

Re-export from cli/src/core/logger.ts exists for migration convenience but new code should import from @tarsk/shared directly.

Validation Checklist

When reviewing code changes that add or modify logging:

Required (blocks merge)

  • All log calls use createLogger from @tarsk/shared -- no raw console.* calls.
  • Logger is created at module scope: const log = createLogger("domain.action");
  • Event name follows dot-notation format, all lowercase, no brackets.
  • Correct log level for the severity (DEBUG/INFO/WARN/ERROR).
  • Message is a short sentence without embedded data.
  • Structured data passed as the second argument, not interpolated into the message.
  • Error objects passed directly, not wrapped in string template.
  • No circular reference hazards in logged data (the logger handles this, but avoid logging DOM nodes or React fiber trees).

Recommended (should fix)

  • Reuses existing domain names when adding to an existing subsystem.
  • DEBUG level for timing/cache/payload data that would be noisy.
  • No logging inside tight loops or render paths without a guard.
  • No sensitive data in logs (API keys, tokens, passwords, PII).

Migration Guide

When converting a file from ad-hoc logging:

  1. Add import { createLogger } from "@tarsk/shared"; (CLI) or same from @tarsk/shared (app).
  2. Add const log = createLogger("domain.action"); after imports.
  3. Replace console.log("[prefix] message") with log.info("message").
  4. Replace console.error("[prefix] message") with log.error("message").
  5. Replace console.warn("[prefix] message") with log.warn("message").
  6. Move interpolated values into the data object.
  7. Remove the [prefix] from the message string.

Skill Execution

To audit an entire subsystem or file:

  1. Use grep to find all console.(log|error|warn|debug) calls in the target files.
  2. For each call, verify it uses createLogger or is inside the logger implementation.
  3. Check the event name, level, message format, and data argument.
  4. Report violations grouped by severity (blocks/should-fix).
  5. Offer to fix violations if the user requests it.

Architecture Notes

  • The shared logger lives in shared/src/logger.ts.
  • It works in both Node.js and browser environments.
  • The CLI entrypoint (cli/src/index.ts) sets the global log level and optionally adds a file transport for debug mode.
  • The frontend can register transports via addLogTransport() for server-side log forwarding.
  • The old cli/src/core/logger.ts Logger class is dead code -- it re-exports from shared now.
  • The old app/lib/voice/utils/Logger.ts has been removed -- replaced by the shared logger.