skills/workflows/SKILL.md
Complete workflow patterns for common TraceMem operations.
npx skillsauth add tracemem/tracemem-skills workflowsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The Decision Envelope is NOT optional.
ALL TraceMem operations MUST happen within a decision envelope:
┌─────────────────────────────────────┐
│ DECISION ENVELOPE (decision_id) │
│ ┌───────────────────────────────┐ │
│ │ ✓ decision_read │ │
│ │ ✓ decision_write (CRUD) │ │
│ │ ✓ decision_evaluate │ │
│ │ ✓ decision_request_approval │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────┘
❌ CANNOT be called without decision_id
Discovery tools (do NOT require decision envelope):
products_list - find available productsproduct_get - get schema and purposescapabilities_get - get runtime capabilitiesUse Case: Get customer details for support ticket
// Step 1: Create Decision Envelope (MANDATORY)
const createResult = await decision_create({
intent: "customer.lookup.support",
automation_mode: "autonomous" // Must be: propose, approve, override, autonomous
});
const decisionId = createResult.decision_id; // Save for all subsequent operations
// Step 2: Get Product Schema (Optional but recommended)
const productInfo = await product_get({
product: "customers_v1"
});
// Returns: {
// exposed_schema: [
// {name: "customer_id", type: "integer"},
// {name: "name", type: "string"},
// {name: "email", type: "string"},
// {name: "tier", type: "string"}
// ],
// allowed_purposes: ["support_context", "order_validation"]
// }
// Step 3: Read Data (REQUIRES decision_id)
const readResult = await decision_read({
decision_id: decisionId, // From Step 1
product: "customers_v1",
purpose: "support_context", // Must be in allowed_purposes
query: {customer_id: 1001}, // Use field names from schema
allow_multiple: false
});
// Returns: {records: [{customer_id: 1001, name: "Acme Corp", ...}]}
// Step 4: Close Decision Envelope (MANDATORY)
await decision_close({
decision_id: decisionId,
action: "commit" // or "abort" if cancelled
});
// ❌ WRONG - This will FAIL
const result = await decision_read({
product: "customers_v1",
purpose: "support_context",
query: {customer_id: 1001}
// Missing decision_id!
});
// Error: "decision_id is required"
// ✓ CORRECT - Create decision first
const createResult = await decision_create({...});
const result = await decision_read({
decision_id: createResult.decision_id,
...
});
Use Case: Create a new customer order
// Step 1: Create Decision Envelope (MANDATORY)
const createResult = await decision_create({
intent: "order.create.customer",
automation_mode: "autonomous"
});
const decisionId = createResult.decision_id;
// Step 2: Get Product Schema to understand required fields
const productInfo = await product_get({
product: "orders_v1"
});
// Check restrictions.write.insert_config.column_config for:
// - required fields
// - allowed fields
// - fields with auto-generation
// Step 3: Insert Data (REQUIRES decision_id)
const writeResult = await decision_write({
decision_id: decisionId, // From Step 1
product: "orders_v1",
purpose: "order_creation",
mutation: {
operation: "insert",
records: [{
customer_id: 1001, // Required field
total_amount: 99.99, // Required field
status: "pending" // Required field
// order_id omitted - auto-generated
}]
}
});
// Returns: {created_records: [{order_id: 12345, ...}]}
// Step 4: Close Decision Envelope (MANDATORY)
await decision_close({
decision_id: decisionId,
action: "commit"
});
Use Case: Update order status to shipped
// Step 1: Create Decision Envelope (MANDATORY)
const createResult = await decision_create({
intent: "order.status.update",
automation_mode: "approve" // Requires approval
});
const decisionId = createResult.decision_id;
// Step 2: Read current state (best practice)
const currentData = await decision_read({
decision_id: decisionId,
product: "orders_v1",
purpose: "order_update",
query: {order_id: 12345}
});
const currentStatus = currentData.records[0].status;
// Step 3: Evaluate policy (if required)
const policyResult = await decision_evaluate({
decision_id: decisionId,
policy_id: "order_status_change_v1",
inputs: {
current_status: currentStatus,
new_status: "shipped"
}
});
// Returns: {allowed: true, ...} or {allowed: false, requires_approval: true}
// Step 4: Update Data (REQUIRES decision_id, using NEW keys format)
const updateResult = await decision_write({
decision_id: decisionId,
product: "orders_v1",
purpose: "order_update",
operation: "update", // Top-level operation
keys: {order_id: 12345}, // NEW: Explicit key specification
mutation: {
fields: { // NEW: Update fields separate from keys
status: "shipped",
shipped_at: new Date().toISOString()
}
}
});
// Step 5: Close Decision Envelope (MANDATORY)
await decision_close({
decision_id: decisionId,
action: "commit"
});
Use Case: Delete expired draft order
// Step 1: Create Decision Envelope (MANDATORY)
const createResult = await decision_create({
intent: "order.draft.cleanup",
automation_mode: "autonomous"
});
const decisionId = createResult.decision_id;
// Step 2: Verify record before delete (best practice)
const verifyResult = await decision_read({
decision_id: decisionId,
product: "orders_v1",
purpose: "data_cleanup",
query: {
order_id: 67890,
status: "draft"
}
});
if (verifyResult.records.length === 0) {
// No record found - abort
await decision_close({
decision_id: decisionId,
action: "abort",
reason: "Record not found or not eligible for deletion"
});
return;
}
// Step 3: Delete Data (REQUIRES decision_id, using NEW keys format)
const deleteResult = await decision_write({
decision_id: decisionId,
product: "orders_v1",
purpose: "data_cleanup",
operation: "delete", // Top-level operation
keys: {order_id: 67890} // NEW: Explicit key specification (no mutation needed for single delete)
});
// Step 4: Close Decision Envelope (MANDATORY)
await decision_close({
decision_id: decisionId,
action: "commit"
});
Use Case: Request approval for exceptional discount
// Step 1: Create Decision Envelope (MANDATORY)
const createResult = await decision_create({
intent: "discount.exception.request",
automation_mode: "approve" // Indicates approval needed
});
const decisionId = createResult.decision_id;
// Step 2: Evaluate policy to check if approval needed
const policyResult = await decision_evaluate({
decision_id: decisionId,
policy_id: "discount_cap_v1",
inputs: {
discount_percent: 30,
customer_tier: "standard",
order_value: 1000
}
});
if (policyResult.requires_approval) {
// Step 3: Request Approval (REQUIRES decision_id)
const approvalResult = await decision_request_approval({
decision_id: decisionId,
title: "30% Discount Exception",
message: "Customer requesting 30% discount on $1000 order. Standard tier typically limited to 15%."
});
// Step 4: Wait for approval (poll decision_get)
let approved = false;
for (let i = 0; i < 60; i++) { // Poll for up to 5 minutes
await sleep(5000); // Wait 5 seconds
const decisionStatus = await decision_get({
decision_id: decisionId
});
if (decisionStatus.approval_status === "approved") {
approved = true;
break;
} else if (decisionStatus.approval_status === "denied") {
break;
}
}
if (!approved) {
// Step 5a: Close with abort if denied
await decision_close({
decision_id: decisionId,
action: "abort",
reason: "Approval denied or timed out"
});
return;
}
}
// Step 5b: Apply the discount (if approved)
const writeResult = await decision_write({
decision_id: decisionId,
product: "discounts_v1",
purpose: "discount_application",
mutation: {
operation: "insert",
records: [{
order_id: 12345,
discount_percent: 30,
reason: "exception_approved"
}]
}
});
// Step 6: Close Decision Envelope (MANDATORY)
await decision_close({
decision_id: decisionId,
action: "commit"
});
Use Case: Get all premium customers for marketing
// Step 1: Create Decision Envelope (MANDATORY)
const createResult = await decision_create({
intent: "customer.list.marketing",
automation_mode: "autonomous"
});
const decisionId = createResult.decision_id;
// Step 2: Read with allow_multiple (REQUIRES decision_id)
const readResult = await decision_read({
decision_id: decisionId,
product: "customers_v1",
purpose: "marketing_campaign",
query: {tier: "premium"},
allow_multiple: true // Allow multiple results
});
console.log(`Found ${readResult.records.length} premium customers`);
// Step 3: Close Decision Envelope (MANDATORY)
await decision_close({
decision_id: decisionId,
action: "commit"
});
When using OpenCode plugin, you can use convenience wrappers:
// OpenCode convenience
const result = await tracemem_open({
action: "db_change" // Maps to intent: "data.change.apply"
});
// Is equivalent to:
const result = await decision_create({
intent: "data.change.apply",
automation_mode: "autonomous"
});
Action Mappings:
edit_files → code.change.applyrefactor → code.refactor.executerun_command → ops.command.executedeploy → deploy.release.executesecrets → secrets.change.proposedb_change → data.change.applyreview → code.review.assist// Problem: Attempted operation without decision envelope
❌ await decision_read({product: "customers_v1", ...});
// Solution: Create decision first
✓ const {decision_id} = await decision_create({...});
✓ await decision_read({decision_id, ...});
// Problem: Used invalid automation mode
❌ await decision_create({
intent: "order.create",
automation_mode: "manual" // Invalid!
});
// Solution: Use one of the 4 valid values
✓ await decision_create({
intent: "order.create",
automation_mode: "autonomous" // Valid: propose, approve, override, autonomous
});
// Problem: Used invalid purpose
❌ await decision_read({
decision_id,
product: "customers_v1",
purpose: "random_purpose" // Not in allowed_purposes
});
// Solution: Check product_get first
✓ const product = await product_get({product: "customers_v1"});
✓ console.log(product.allowed_purposes); // ["support_context", "order_validation"]
✓ await decision_read({
decision_id,
product: "customers_v1",
purpose: "support_context" // Use valid purpose
});
// Problem: Used wrong field name in query
❌ await decision_read({
decision_id,
product: "customers_v1",
query: {customerId: 1001} // Wrong field name
});
// Solution: Check schema first
✓ const product = await product_get({product: "customers_v1"});
✓ console.log(product.exposed_schema); // [{name: "customer_id", ...}]
✓ await decision_read({
decision_id,
product: "customers_v1",
query: {customer_id: 1001} // Correct field name from schema
});
| Operation | Requires decision_id? | What It Returns | When to Use |
|-----------|----------------------|-----------------|-------------|
| decision_create | ❌ No (creates it) | decision_id | FIRST STEP - Always start here |
| products_list | ❌ No | List of product names | Discovery - find available products |
| product_get | ❌ No | METADATA about product (schema, purposes) | Discovery - understand product structure |
| decision_read | ✅ YES | ACTUAL DATA records from database | Read actual customer/order/etc records |
| decision_write | ✅ YES | Write confirmation | Insert/Update/Delete actual data |
| decision_evaluate | ✅ YES | Policy decision | Check if action is allowed |
| decision_request_approval | ✅ YES | Approval request ID | Request human approval |
| decision_close | ✅ YES | Closure confirmation | FINAL STEP - Always close |
Always create decision first: No exceptions. All operations require a decision envelope.
Understand product structure first: Call product_get to get METADATA (schema, purposes). This tells you HOW to query, not the data itself. Then use decision_read to get ACTUAL DATA.
Choose correct write operation:
operation: "insert", mutation: {records: [...]}operation: "update", keys: {...}, mutation: {fields: {...}}operation: "delete", keys: {...}Close every decision: Use try/finally to ensure decisions are closed even on errors.
Use meaningful intents: Follow pattern domain.entity.action (e.g., customer.order.create).
Only 4 automation modes: propose, approve, override, autonomous - no others are valid.
Read before update/delete: For updates/deletes, always read current state first to verify the record exists.
Handle errors gracefully: Close with "abort" if operation fails or is cancelled.
Critical distinction:
// product_get → Returns METADATA about the product
const metadata = await product_get({product: "customers_v1"});
// Returns: {
// exposed_schema: [{name: "customer_id", type: "integer"}, ...],
// allowed_purposes: ["support_context", ...],
// example_queries: [...]
// }
// This tells you HOW the product works, not the actual data
// decision_read → Returns ACTUAL DATA from the product
const data = await decision_read({
decision_id,
product: "customers_v1",
purpose: "support_context",
query: {customer_id: 1001}
});
// Returns: {
// records: [{customer_id: 1001, name: "Acme Corp", email: "[email protected]"}]
// }
// This gives you the actual customer record
Think of it like a library:
product_get = Reading the card catalog to understand what's availabledecision_read = Actually checking out and reading a bookWhen using decision_write, provide the operation as a top-level parameter:
Use when: You want to add a NEW record that doesn't exist yet
// Top-level operation parameter (NEW)
operation: "insert",
mutation: {
records: [{
customer_id: 1001, // Required fields from schema
name: "Acme Corp",
email: "[email protected]"
// order_id omitted if auto-generated
}]
}
Use when: You want to CHANGE specific fields in records that already exist
// NEW recommended format: keys object (single record)
operation: "update",
keys: {order_id: 12345}, // Explicit key specification
mutation: {
fields: { // Update fields separate from keys
status: "shipped",
shipped_at: "2026-02-03T10:00:00Z"
}
}
// OR batch format with keys array
operation: "update",
keys: ["order_id"], // Declare key field names
mutation: {
records: [{
order_id: 12345,
status: "shipped",
shipped_at: "2026-02-03T10:00:00Z"
}]
}
Use when: You want to REMOVE records entirely
// NEW recommended format: keys object (simplest for single delete)
operation: "delete",
keys: {order_id: 67890} // Explicit key specification
// OR batch format with keys array
operation: "delete",
keys: ["order_id"],
mutation: {
records: [{
order_id: 67890
}, {
order_id: 67891
}]
}
Note: The new keys parameter makes update/delete requests self-documenting and clear. For backward compatibility, the old format (keys mixed with fields) still works but is deprecated. Always use explicit key specification for better clarity and maintainability.
Rule of thumb:
testing
Instructions for writing and efficiently storing data in TraceMem.
tools
Scenarios where TraceMem should not be used.
development
Auditing memory traces and debugging.
data-ai
Understanding safety constraints and handling failures.