projections

Build or query TES projections (current state views). State is derived from TES events - projections are the queryable current truth.

16 stars

Best use case

projections is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Build or query TES projections (current state views). State is derived from TES events - projections are the queryable current truth.

Teams using projections should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/projections/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/tools/projections/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/projections/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How projections Compares

Feature / AgentprojectionsStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Build or query TES projections (current state views). State is derived from TES events - projections are the queryable current truth.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Projections Skill

## Core Principle

**State is derived from TES events. Projections are the queryable current truth.**

---

## Projection Types

| Projection | Purpose | Key |
|------------|---------|-----|
| ItemCurrentState | Current state of an item | item canonical_id |
| ListingCurrentState | Current listing status | listing canonical_id |
| ParticipantInventory | What a user owns | participant canonical_id |
| CampaignState | Campaign metrics | campaign canonical_id |

---

## Durable Object Pattern

```javascript
// workers/projections/ItemProjection.js

export class ItemProjection {
  constructor(state, env) {
    this.state = state;
    this.env = env;
  }

  async fetch(request) {
    const url = new URL(request.url);

    if (request.method === "GET") {
      const currentState = await this.state.storage.get("state");
      return Response.json(currentState || { error: "Not found" });
    }

    if (request.method === "POST" && url.pathname === "/apply-event") {
      const event = await request.json();
      return this.applyEvent(event);
    }
  }

  async applyEvent(event) {
    // Idempotency check
    const processedEvents = await this.state.storage.get("processed") || [];
    if (processedEvents.includes(event.id)) {
      return Response.json({ status: "already_processed" });
    }

    // Get current state
    let state = await this.state.storage.get("state") || this.initialState();

    // Apply event
    state = this.reduce(state, event);
    state.last_event_id = event.id;
    state.last_updated = event.timestamp;

    // Save
    await this.state.storage.put("state", state);
    await this.state.storage.put("processed", [...processedEvents.slice(-100), event.id]);

    return Response.json({ status: "applied", state });
  }

  reduce(state, event) {
    switch (event.type) {
      case "item.captured":
        return { ...state, status: "captured", media: event.payload.image_urls };
      case "item.identified":
        return { ...state, status: "identified", product_ref: event.payload.product_ref };
      case "item.listed":
        return { ...state, status: "listed", listing_id: event.payload.listing_id };
      case "item.sold":
        return { ...state, status: "sold", sold_at: event.timestamp };
      default:
        return state;
    }
  }

  initialState() {
    return { status: "unknown", created_at: new Date().toISOString() };
  }
}
```

---

## Querying Projections

```javascript
// Get current item state
async function getItemState(env, itemId) {
  const doId = env.ITEM_PROJECTION.idFromName(itemId);
  const stub = env.ITEM_PROJECTION.get(doId);

  const response = await stub.fetch(new Request("https://do/"));
  return response.json();
}

// In API handler
const itemState = await getItemState(env, "ptc_item_abc123");
```

---

## TES Router (Event Fan-out)

```javascript
// workers/tes-router.js

export default {
  async queue(batch, env) {
    for (const message of batch.messages) {
      const event = message.body;

      // Route to appropriate projections
      const routes = getRoutes(event);

      await Promise.all(routes.map(async (route) => {
        const doId = env[route.binding].idFromName(route.key);
        const stub = env[route.binding].get(doId);

        await stub.fetch(new Request("https://do/apply-event", {
          method: "POST",
          body: JSON.stringify(event),
        }));
      }));

      message.ack();
    }
  },
};

function getRoutes(event) {
  const routes = [];

  if (event.entity_type === "item") {
    routes.push({ binding: "ITEM_PROJECTION", key: event.entity_id });
  }

  if (event.type === "item.sold") {
    routes.push({ binding: "LISTING_PROJECTION", key: event.payload.listing_id });
    routes.push({ binding: "PARTICIPANT_PROJECTION", key: event.payload.seller_id });
    routes.push({ binding: "PARTICIPANT_PROJECTION", key: event.payload.buyer_id });
  }

  return routes;
}
```

---

## Anti-Patterns

- Querying D1 for "current truth" instead of projections
- Mutating projection state without event
- Global projections (hot-key bottleneck)
- Not handling idempotency

Related Skills

startup-business-analyst-financial-projections

16
from diegosouzapw/awesome-omni-skill

Create detailed 3-5 year financial model with revenue, costs, cash flow, and scenarios

bgo

16
from diegosouzapw/awesome-omni-skill

Automated Blender build-go workflow. Automatically builds, removes old version, installs, enables, and launches Blender with your extension/add-on. Use when you want to quickly test changes, execute complete build-to-launch cycle, or run custom packaging scripts with automatic Blender launch.

Coding & Development

maintenance

16
from diegosouzapw/awesome-omni-skill

Cleans up and organizes project files. Use when user mentions '整理', 'cleanup', 'アーカイブ', 'archive', '肥大化', 'Plans.md', 'session-log', or asks to clean up old tasks, archive completed items, or organize files. Do NOT load for: 実装作業, レビュー, 新機能開発, デプロイ.

hello-skill

16
from diegosouzapw/awesome-omni-skill

每次对话开始时,声明"[Skills✏️已加载]"

zylvie-automation

16
from diegosouzapw/awesome-omni-skill

Automate Zylvie tasks via Rube MCP (Composio). Always search tools first for current schemas.

zoominfo-automation

16
from diegosouzapw/awesome-omni-skill

Automate Zoominfo tasks via Rube MCP (Composio). Always search tools first for current schemas.

zoho-invoice-automation

16
from diegosouzapw/awesome-omni-skill

Automate Zoho Invoice tasks via Rube MCP (Composio): invoices, estimates, expenses, clients, and payment tracking. Always search tools first for current schemas.

zoho-inventory-automation

16
from diegosouzapw/awesome-omni-skill

Automate Zoho Inventory tasks via Rube MCP (Composio): items, orders, warehouses, shipments, and stock management. Always search tools first for current schemas.

zoho-bigin-automation

16
from diegosouzapw/awesome-omni-skill

Automate Zoho Bigin tasks via Rube MCP (Composio): pipelines, contacts, companies, products, and small business CRM. Always search tools first for current schemas.

zoho_desk-automation

16
from diegosouzapw/awesome-omni-skill

Zoho Desk automation via Rube MCP -- toolkit not currently available in Composio; no ZOHO_DESK_ tools found

zoho-automation

16
from diegosouzapw/awesome-omni-skill

Automate Zoho tasks via Rube MCP (Composio). Always search tools first for current schemas.

zeroclaw

16
from diegosouzapw/awesome-omni-skill

Comprehensive operational knowledge for ZeroClaw, the fast, small, fully autonomous AI assistant infrastructure built in Rust. Covers CLI, 30 providers, 14 channels, config, hardware, deployment, and security.