OR Key
drop another .md file to compare - side-by-side diff against mine

mine

Pulls reusable material out of your meetings and work.
description: "Triggers on prompt mention of 'mine'."
personal 2 files 10 recent evals

What it does for you

Pulls reusable material out of your meetings and work.

What it produces

A recent result, so you can see the kind of work it returns.

loading…

How to get it

These run inside the Snappy workspace. Want this working in your business? I set skills like this up with you, in one focused week.

Work with me
For developers how this skill is built, graded, and how it runs

at a glance- the short version

actorExported functions in state/lib/mine.ts.
auditorNone wired yet - eval is manual (Robert review).
eval modeshape
categoryContent
stages2
dependscontent-engine

what's inside - the parts that make up a skill 3/4 present

A skill is just a few plain-text files. Only the main one is required. The rest are optional, added as the work needs them. This is what the skill is made of; how it runs is just below.

The skill
state/skills/mine/SKILL.md present
the skill itself, in plain text
The main file. It says what the skill is and lays out the steps in plain English.
Code
state/lib/mine.ts present
code the skill can run
Reusable code this skill can call when it needs to.
Scripts
state/bin/mine/ not present
helper scripts
Optional. Added when a skill has a few commands to run.
Loader
state/skills/mine/AGENTS.md present
what the AI loads on the fly
Loaded automatically the moment this skill is needed. Kept short on purpose.

how it's graded - what counts as a good run 3 criteria · 2 deterministic · 1 judge

Each row is one thing a good run has to get right. deterministic means a quick check decides, pass or fail. judge means the AI reads the result and rates it. Grading each piece on its own (instead of one overall score) shows exactly where a run fell short, so the fix is obvious.

name
kind
check
correct_function_call_trace
deterministic
The execution log verifies that the correct mining function from 'state/lib/mine.ts' was invoked based on the input provided.
no_errors_in_log
deterministic
The 'state/log/pending-eval.ndjson' entry or skill execution logs contain no error messages related to the mining operation.
output_matches_expected_shape
judge
The output structure produced by the mining function matches the expected data shape for the given operation.

how it runs - the shared frame every skill uses 5/5 present

Every skill runs the same way. One part does the work, a separate part checks it, and a short loader hands the AI exactly what it needs for the job. Anything this skill doesn't use shows a one-line note saying why, on purpose, not by accident.

makes the work The worker
present
Exported functions in state/lib/mine.ts. the worker
Does the actual work. Whatever it produces is what gets checked next.
checks the work The reviewer
present
None wired yet - eval is manual (Robert review). the checker
A separate checker grades the work, so the part that made it can't approve its own work.
frame
learns Self-correction
present
fixes itself learns from gaps
When a run hits a gap, the skill gets edited on the spot [FIXED] or queued for a bigger rewrite [LOGGED], so it keeps getting better.
tidies up Background fixes
present
queued for rewrite runs in the background
Bigger fixes that can't be made on the spot get queued and rewritten in the background later.
remembers Run history
present
state/log/pending-eval.ndjson pending runs
Every run is written down here, then reviewed by hand each week.
Critical rules the things this skill must not get wrong
  1. Mining drafts must CITE, never paraphrase — verbatim stitching from transcripts, plus checkTone + requireCitations gates before return (carryover rule from kernel mining pods)
  2. Extract Robert-signal: what Robert demos / brings up / repeats — not generic patterns. Do not surface decoy author-scoreboard counts.
  3. Mining "next moves" are RAW SIGNAL, not action plans — always filter through Robert's positioning before drafting client-facing output
  4. This is a Phase 0.5 port; the state/lib/mine.ts surface is mechanical. The kernel snappy-mine had richer mining-pod shape; cross-reference that .md if details are missing.

what it has learned - fixes written back in over time sample

When a run hits something this skill didn't handle, the fix gets written back into the skill so it doesn't happen again. FIXED means it was corrected on the spot. LOGGED means it's queued for a bigger rewrite. Either way, the skill gets a little better and never makes the same mistake twice.

  1. Loading feedback rows…

how the work flows- who makes it, who checks it

inputs content-engine
actor Exported functions in state/lib/mine.ts.
1 generator
invoke
actor = Exported functions in state/lib/mine.ts.
import from `state/lib/mine.ts` — `meetingsByParticipant`, `listAllTranscripts`, `listPendingTranscripts`, `getMineFiles`, `getManifest`, `getMinedSources`, `persistNuggets`, `computeMineMetric
auditor None wired yet - eval is manual (Robert review).
2 data
eval log
`state/log/pending-eval.ndjson` (manual review until shape gate added)

SKILL.md- the skill, written out in plain English

mine

Content mining operations for all snappy-* skills.

Ported from kernel snappy-mine in Phase 0.5. See state/lib/mine.ts for the full API surface.

Steps

  • meetingsByParticipant() - see state/lib/mine.ts
  • listAllTranscripts() - see state/lib/mine.ts
  • listPendingTranscripts() - see state/lib/mine.ts
  • getMineFiles() - see state/lib/mine.ts
  • getManifest() - see state/lib/mine.ts
  • getMinedSources() - see state/lib/mine.ts
  • persistNuggets() - see state/lib/mine.ts
  • computeMineMetric() - see state/lib/mine.ts

Eval

Actor: the exported functions in state/lib/mine.ts. Auditor: none wired yet - eval is manual (Robert review). File a state/log/pending-eval.ndjson row on each run.

Score convention:

OutcomeScore
Pass on first try1.0
Failed first, auto-fix applied, re-check passed0.5
Still failing or unrecoverable0.0

Gotchas

via the Phase 0.5 driver. Only these rewrites were applied: already in state/lib/)

  1. realpathSync(process.argv[1]) CLI guard wrapped in try/catch
  • See the kernel SKILL.md for the original long-form guidance if you need it

(read-only reference at the kernel path above).

Graduation

This skill is prose. Graduate by defining a deterministic auditor and flipping eval: auto.

Rubric

criteria:
  - name: correct_function_call_trace
    kind: deterministic
    check: "The execution log verifies that the correct mining function from 'state/lib/mine.ts' was invoked based on the input provided."
  - name: no_errors_in_log
    kind: deterministic
    check: "The 'state/log/pending-eval.ndjson' entry or skill execution logs contain no error messages related to the mining operation."
  - name: output_matches_expected_shape
    kind: judge
    check: "The output structure produced by the mining function matches the expected data shape for the given operation."

AGENTS.md- what the AI loads when this skill comes up

mine - loader

Per-turn rules for the mine skill. Full reference: state/skills/mine/SKILL.md. Do not skip these.

Critical Rules

  • Mining drafts must CITE, never paraphrase - verbatim stitching from transcripts, plus checkTone + requireCitations gates before return (carryover rule from kernel mining pods)
  • Extract Robert-signal: what Robert demos / brings up / repeats - not generic patterns. Do not surface decoy author-scoreboard counts.
  • Mining "next moves" are RAW SIGNAL, not action plans - always filter through Robert's positioning before drafting client-facing output
  • This is a Phase 0.5 port; the state/lib/mine.ts surface is mechanical. The kernel snappy-mine had richer mining-pod shape; cross-reference that .md if details are missing.

Commands

| ui dashboard | state/skills/mine/resources/ui.openui | |invoke: import from state/lib/mine.ts - meetingsByParticipant, listAllTranscripts, listPendingTranscripts, getMineFiles, getManifest, getMinedSources, persistNuggets, computeMineMetric |eval log: state/log/pending-eval.ndjson (manual review until shape gate added) |related: state/skills/content-mine/SKILL.md (the auto-eval mining verb with requireCitations() gate)

OpenUI Resource

  • Skill-owned OpenUI Lang resource: state/skills/mine/resources/ui.openui. Read it before rendering or editing this skill's generated component surface.
  • Treat this resource as a first-class artifact of the skill, not a generic chat response. Improve it when the skill's user-facing output needs to become richer.
  • System resources compose OpenUI primitives and inherit SnappyChat tokens. Use ui_contract: branded in SKILL.md only for deliberate platform or client visuals.

Known Pitfalls

  • Skill frontmatter says eval: shape but no auditor is wired - must log pending-eval.ndjson
  • The verb the agent usually wants is content-mine (graduated, requireCitations gate). Reach for mine only when the lower-level transcript/manifest functions are needed.
  • Author-scoreboard numbers ("620 endpoints", "14 clients") cringe Robert - restructure as observations about the work

Self-Test

An agent reading this should correctly:

  1. [ ] Pick content-mine over mine for client-facing draft generation?
  2. [ ] Cite verbatim instead of paraphrasing transcript content?
  3. [ ] Strip self-counts of output ("X endpoints built") before surfacing?

Self-report

If this loader fell short, append a line:

echo "[$(date -u +%FT%TZ)] mine: <what was missing>" >> state/log/loader-feedback.log

<!-- kernel-ok: historical attribution for the PID-loader pattern. -->

Self-correcting loader (PID feedback)

This is the rule that makes loaders learn. Ported from snappy-kernel, where it demonstrably worked: the snappy-dom-cartographer skill mapped Skool admin UI once, every later ship-agent inherited the full map for free.

Before you finish, do two things:

1. Fix gaps (P - proportional). MANDATORY. If this loader didn't cover your case - if you had to read another file, run an undocumented command, work around a wrong selector, or discover a quirk - you MUST attempt an Edit to this AGENTS.md before you log.

  • Default action: edit this file. Surgical. Add the missing line, table

row, or code example where it belongs. No restructuring.

  • Only LOGGED is allowed when: the fix needs >10 lines, spans multiple

files, or requires a structural rewrite. In that case the state/regen/drain.sh queue picks it up asynchronously.

  • "I didn't have time" / "it's minor" / "the next agent will figure it out"

are NOT valid reasons. Minor gaps compound - that's the whole point of this loop.

  • Concrete example of a valid P-fix: discover agent-browser screenshot

takes path positionally not as --output <path>. One line in a table. Edit it in. Do not just log it.

  • The goal: the next agent never has to leave the loader.

2. Log the result.

echo "[$(date -u +%FT%TZ)] mine: <what was missing or fixed> [FIXED|LOGGED]" >> state/log/loader-feedback.log
  • FIXED = you patched this loader inline (P-fix).
  • LOGGED = too large for inline; the PostToolUse enqueue + Stop-hook drain

will rewrite the loader from scratch on next session-end.

Do not skip this. Every agent run must leave the system better than it found it. The loader is the setpoint; you are the sensor; the gap is the error signal; closing the gap is the correction.

api.ts- the code it can call

#!/usr/bin/env npx tsx
/**
 * snappy-mine/api.ts -- Content mining operations for all snappy-* skills.
 *
 * Usage:
 *   npx tsx api.ts manifest                     # show manifest.json
 *   npx tsx api.ts sources                       # list all mined source files
 *   npx tsx api.ts files                         # list framework-mine-*.json files
 *   npx tsx api.ts persist deep-ray-sessions.json # persist nuggets to content engine DB
 *
 * Or import as module:
 *   import { getMineFiles, getManifest, persistNuggets } from "./mine.ts";
 */

import { existsSync, readFileSync, readdirSync, realpathSync, statSync } from "fs";
import { join } from "path";
import { execSync } from "child_process";
import { env } from "./env.ts";

const MINED_DIR = join(process.env.HOME!, ".claude/corpus/mined");
const MANIFEST_PATH = join(MINED_DIR, "manifest.json");
const KRISP_DIR = join(process.env.HOME!, ".claude/corpus/krisp");
const KRISP_INDEX = join(KRISP_DIR, "index.json");
const SPEAKER_MAP_PATH = join(process.env.HOME!, ".claude/skills/snappy-mine/speaker-map.json");

// ---------------------------------------------------------------------------
// meetingsByParticipant
// ---------------------------------------------------------------------------

export interface MeetingMatch {
  meeting_id: string;
  date: string;
  title: string;
  participants: string[];
  transcript_path: string;
}

interface SpeakerMapEntry {
  full_name?: string;
  aliases?: string[];
  email?: string;
  linkedin?: string | null;
  xano_contact_id?: number | null;
}

function loadSpeakerMap(): Record<string, SpeakerMapEntry> {
  if (!existsSync(SPEAKER_MAP_PATH)) return {};
  try {
    return JSON.parse(readFileSync(SPEAKER_MAP_PATH, "utf-8"));
  } catch {
    return {};
  }
}

/**
 * Parse frontmatter of a Krisp transcript + scrape speaker lines (`**Name | mm:ss**`).
 * Returns the union of frontmatter attendees and in-transcript speakers.
 * Reads only the first ~16KB of the file — enough for frontmatter + dozens of speaker lines.
 */
function readMeetingMeta(absPath: string): {
  meeting_id: string;
  date: string;
  title: string;
  participants: string[];
} | null {
  let raw: string;
  try {
    const fd = readFileSync(absPath, "utf-8");
    raw = fd.slice(0, 16_000);
  } catch {
    return null;
  }

  let meeting_id = "";
  let date = "";
  let title = "";
  const fmAttendees: string[] = [];

  const fmMatch = raw.match(/^---\n([\s\S]*?)\n---/);
  if (fmMatch) {
    const fm = fmMatch[1];
    const idM = fm.match(/meeting_id:\s*(\S+)/);
    if (idM) meeting_id = idM[1];
    const dateM = fm.match(/date:\s*(\S+)/);
    if (dateM) date = dateM[1];
    const nameM = fm.match(/name:\s*"?([^"\n]+?)"?\s*$/m);
    if (nameM) title = nameM[1].trim();
    const attM = fm.match(/attendees:\s*\[([^\]]*)\]/);
    if (attM && attM[1].trim()) {
      for (const piece of attM[1].split(",")) {
        const cleaned = piece.trim().replace(/^["']|["']$/g, "");
        if (cleaned) fmAttendees.push(cleaned);
      }
    }
  }

  // Scrape speaker lines: **Name | 04:18**
  const speakerSet = new Set<string>(fmAttendees);
  const speakerRe = /\*\*([^*|]+?)\s*\|\s*\d{1,2}:\d{2}\*\*/g;
  let m: RegExpExecArray | null;
  while ((m = speakerRe.exec(raw)) !== null) {
    const name = m[1].trim();
    if (name && !/^speaker\s*\d+$/i.test(name)) speakerSet.add(name);
  }

  return {
    meeting_id,
    date,
    title,
    participants: Array.from(speakerSet),
  };
}

/**
 * Find Krisp meetings where a given participant appears.
 * Matching precedence:
 *   1. exact email (via speaker-map lookup)
 *   2. exact name (case-insensitive)
 *   3. fuzzy name (substring, case-insensitive)
 *
 * Returns MeetingMatch[] sorted by date desc. Capped at 50 results.
 * Source of truth is the Krisp index.json — we only open transcript files
 * whose filename already hints at a name match, then verify via scraped participants.
 *
 * NOTE: `recent_meetings` in snappy-knowledge.resolvePerson is currently []
 * because this function did not exist. This is its backing store.
 */
export function meetingsByParticipant(
  handle: string,
  opts: { limit?: number } = {}
): MeetingMatch[] {
  if (!existsSync(KRISP_INDEX)) return [];

  const limit = opts.limit ?? 50;
  const speakerMap = loadSpeakerMap();

  // Resolve handle → set of candidate names to match against
  const candidateNames = new Set<string>();
  const isEmail = handle.includes("@");

  if (isEmail) {
    for (const [key, entry] of Object.entries(speakerMap)) {
      if (entry?.email?.toLowerCase() === handle.toLowerCase()) {
        candidateNames.add(key.toLowerCase());
        if (entry.full_name) candidateNames.add(entry.full_name.toLowerCase());
        for (const a of entry.aliases ?? []) candidateNames.add(a.toLowerCase());
      }
    }
    if (candidateNames.size === 0) return []; // no email → can't match transcripts
  } else {
    candidateNames.add(handle.toLowerCase());
    // Pull aliases from speaker map if this key exists
    for (const [key, entry] of Object.entries(speakerMap)) {
      const allNames = [key, entry?.full_name, ...(entry?.aliases ?? [])]
        .filter(Boolean)
        .map((s) => (s as string).toLowerCase());
      if (allNames.includes(handle.toLowerCase())) {
        for (const n of allNames) candidateNames.add(n);
      }
    }
  }

  const index: Record<string, string> = JSON.parse(readFileSync(KRISP_INDEX, "utf-8"));
  const results: MeetingMatch[] = [];

  // First pass: filename substring filter (cheap) against any candidate name token
  const nameTokens = new Set<string>();
  for (const n of candidateNames) {
    for (const tok of n.split(/\s+/)) {
      if (tok.length >= 3) nameTokens.add(tok);
    }
  }

  for (const [meeting_id, relPath] of Object.entries(index)) {
    const lowerPath = relPath.toLowerCase();
    const filenameHit = Array.from(nameTokens).some((tok) => lowerPath.includes(tok));

    // Always open the file if filename hits; otherwise skip (too expensive to scan all)
    if (!filenameHit) continue;

    const absPath = join(KRISP_DIR, relPath);
    if (!existsSync(absPath)) continue;

    const meta = readMeetingMeta(absPath);
    if (!meta) continue;

    // Verify: does any participant match a candidate name (exact or fuzzy)?
    const participantsLower = meta.participants.map((p) => p.toLowerCase());
    let matched = false;
    for (const cand of candidateNames) {
      if (participantsLower.includes(cand)) { matched = true; break; } // exact
    }
    if (!matched) {
      for (const cand of candidateNames) {
        if (participantsLower.some((p) => p.includes(cand) || cand.includes(p))) {
          matched = true; break;
        }
      }
    }
    if (!matched) continue;

    results.push({
      meeting_id: meta.meeting_id || meeting_id,
      date: meta.date,
      title: meta.title || relPath,
      participants: meta.participants,
      transcript_path: absPath,
    });
  }

  results.sort((a, b) => (b.date || "").localeCompare(a.date || ""));
  return results.slice(0, limit);
}

/** Walk ~/.claude/corpus/krisp/YYYY/MM/*.md and return raw transcript paths. */
export function listAllTranscripts(): string[] {
  const out: string[] = [];
  if (!existsSync(KRISP_DIR)) return out;
  for (const year of readdirSync(KRISP_DIR)) {
    const yearDir = join(KRISP_DIR, year);
    let stat;
    try { stat = statSync(yearDir); } catch { continue; }
    if (!stat.isDirectory()) continue;
    for (const month of readdirSync(yearDir)) {
      const monthDir = join(yearDir, month);
      try { if (!statSync(monthDir).isDirectory()) continue; } catch { continue; }
      for (const f of readdirSync(monthDir)) {
        if (f.endsWith(".md") && !f.endsWith(".summary.md") && !f.endsWith(".nuggets.json")) {
          out.push(join(monthDir, f));
        }
      }
    }
  }
  return out;
}

/** Returns transcripts that are NOT yet referenced in mined/manifest.json. */
export function listPendingTranscripts(opts: { limit?: number } = {}): string[] {
  const all = listAllTranscripts();
  const manifest = getManifest();
  const minedNames = new Set<string>();
  for (const [key, entry] of Object.entries(manifest)) {
    if (key === "_skipped") {
      for (const s of (entry as any[]) || []) minedNames.add(typeof s === "string" ? s : s.file);
      continue;
    }
    for (const s of (entry as any)?.source_files || []) minedNames.add(s);
  }
  const pending = all
    .filter((p) => !minedNames.has(p.split("/").pop() || ""))
    .sort((a, b) => statSync(b).mtimeMs - statSync(a).mtimeMs);
  return opts.limit ? pending.slice(0, opts.limit) : pending;
}

/** Lists framework-mine-*.json files in the mined directory. */
export function getMineFiles(): string[] {
  if (!existsSync(MINED_DIR)) return [];
  return readdirSync(MINED_DIR)
    .filter((f) => f.startsWith("framework-mine-") && f.endsWith(".json"))
    .sort();
}

/** Reads and returns the manifest.json contents. */
export function getManifest(): Record<string, unknown> {
  if (!existsSync(MANIFEST_PATH)) return {};
  return JSON.parse(readFileSync(MANIFEST_PATH, "utf-8"));
}

/** Extracts all mined source files from the manifest. */
export function getMinedSources(): string[] {
  const manifest = getManifest();
  const sources: string[] = [];
  const sf = manifest.source_files;
  if (Array.isArray(sf)) return sf;
  if (sf && typeof sf === "object") {
    for (const v of Object.values(sf as Record<string, unknown>)) {
      if (Array.isArray(v)) sources.push(...v);
      else if (typeof v === "string") sources.push(v);
    }
  }
  return sources;
}

/** Persists nuggets from a JSON file to the content engine DB via persist-nuggets.ts. */
export function persistNuggets(jsonPath: string): string {
  const absPath = jsonPath.startsWith("/") ? jsonPath : join(MINED_DIR, jsonPath);
  if (!existsSync(absPath)) throw new Error(`File not found: ${absPath}`);
  const script = join(process.env.HOME!, ".claude/skills/snappy-mine/persist-nuggets.ts");
  return execSync(`npx tsx ${script} ${absPath}`, { encoding: "utf-8", timeout: 60_000 });
}

// --- Metrics (Step 7a) ---

const STAGED_ACTIONS_LOG = join(process.env.HOME!, ".claude/logs/staged-actions.ndjson");

type StagedRun = { ts: string; name: string; action: string };

function readStagedRunsMine(): StagedRun[] {
  if (!existsSync(STAGED_ACTIONS_LOG)) return [];
  const out: StagedRun[] = [];
  for (const line of readFileSync(STAGED_ACTIONS_LOG, "utf-8").split("\n")) {
    if (!line.trim()) continue;
    try {
      const j = JSON.parse(line);
      if (typeof j?.name === "string" && typeof j?.ts === "string") {
        out.push({ ts: j.ts, name: j.name, action: j.action || "" });
      }
    } catch { /* skip */ }
  }
  return out;
}

function withinLastDays(tsIso: string, days: number): boolean {
  const t = new Date(tsIso).getTime();
  if (isNaN(t)) return false;
  return t >= Date.now() - days * 86400_000;
}

export function computeMineMetric(name: string): number | null {
  const runs = readStagedRunsMine().filter((r) => withinLastDays(r.ts, 7));
  switch (name) {
    case "runs-per-week":
    case "mine_runs_per_week":
      return runs.filter((r) => r.name === "content-mine").length;
    case "success-rate":
    case "mine_success_rate": {
      const mine = runs.filter((r) => r.name === "content-mine");
      if (!mine.length) return null;
      return mine.filter((r) => r.action !== "error").length / mine.length;
    }
    default:
      return null;
  }
}

// --- CLI ---

if ((() => { try { return import.meta.url === `file://${realpathSync(process.argv[1])}`; } catch { return false; } })()) {
  (async () => {
    const [, , cmd, ...args] = process.argv;

    switch (cmd) {
      case "metrics": {
        const [name, ...rest] = args;
        if (!name) {
          console.error("Usage: api.ts metrics <name> [--json]");
          console.error("Names: runs-per-week, success-rate");
          process.exit(1);
        }
        const value = computeMineMetric(name);
        if (rest.includes("--json")) console.log(JSON.stringify({ value }));
        else console.log(value == null ? "null" : String(value));
        break;
      }
      case "files": {
        const files = getMineFiles();
        console.log(`${files.length} framework-mine files:`);
        for (const f of files) console.log(`  ${f}`);
        break;
      }
      case "manifest": {
        const m = getManifest();
        console.log(JSON.stringify(m, null, 2));
        break;
      }
      case "sources": {
        const sources = getMinedSources();
        console.log(`${sources.length} mined sources:`);
        for (const s of sources) console.log(`  ${s}`);
        break;
      }
      case "pending": {
        const limit = args[0] ? parseInt(args[0], 10) : undefined;
        const pending = listPendingTranscripts(limit ? { limit } : {});
        if (args.includes("--json")) { console.log(JSON.stringify(pending, null, 2)); break; }
        console.log(`${pending.length} unmined transcripts:`);
        for (const p of pending) console.log(`  ${p.replace(process.env.HOME!, "~")}`);
        break;
      }
      case "meetings-by": {
        const [handle, limitStr] = args;
        if (!handle) { console.error("Usage: api.ts meetings-by <name|email> [limit]"); process.exit(1); }
        const limit = limitStr ? parseInt(limitStr, 10) : 20;
        const results = meetingsByParticipant(handle, { limit });
        console.log(JSON.stringify(results, null, 2));
        break;
      }
      case "persist": {
        const [path] = args;
        if (!path) { console.error("Usage: api.ts persist <json-file>"); process.exit(1); }
        const output = persistNuggets(path);
        console.log(output);
        break;
      }
      default:
        console.log("Usage: npx tsx api.ts [files|manifest|sources|persist] ...");
    }
  })();
}

scripts- helper scripts it can run

prose-only skill - 1 inline code block live in SKILL.md above (no state/bin/ sidecar yet).

how we check it- the checks, plus the last 10 runs

rubric shape schema-shape check (no inline rubric)
recent mean 1.00 · 10 runs actor/auditor: unverifiable
deps content-engine
timestamp verb score primary_issue artifact
2026-04-25 04:11Z - 1.00 - -
2026-04-21 15:58Z - 1.00 - -
2026-04-21 15:56Z - 1.00 - -
2026-04-21 03:53Z - 1.00 - -
2026-04-25 04:11Z - 1.00 - -
2026-04-21 15:58Z - 1.00 - -
2026-04-21 15:56Z - 1.00 - -
2026-04-21 03:53Z - 1.00 - -
2026-04-25 04:11Z - 1.00 - -
2026-04-21 15:58Z - 1.00 - -