struere 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16904,8 +16904,11 @@ async function syncOrganization(payload) {
16904
16904
  const error = await response.text();
16905
16905
  return { success: false, error };
16906
16906
  }
16907
- const result = await response.json();
16908
- return result;
16907
+ const json = await response.json();
16908
+ if (json.status === "success" && json.value) {
16909
+ return json.value;
16910
+ }
16911
+ return { success: false, error: "Unexpected response format" };
16909
16912
  }
16910
16913
  async function getSyncState() {
16911
16914
  const credentials = loadCredentials();
@@ -16954,8 +16957,11 @@ async function deployAllAgents() {
16954
16957
  const error = await response.text();
16955
16958
  return { success: false, error };
16956
16959
  }
16957
- const result = await response.json();
16958
- return result;
16960
+ const json = await response.json();
16961
+ if (json.status === "success" && json.value) {
16962
+ return json.value;
16963
+ }
16964
+ return { success: false, error: "Unexpected response format" };
16959
16965
  }
16960
16966
 
16961
16967
  // src/cli/commands/login.ts
@@ -17325,10 +17331,10 @@ function getIndexTs(type) {
17325
17331
  function getToolsIndexTs() {
17326
17332
  return `import { defineTools } from 'struere'
17327
17333
 
17328
- export const tools = defineTools([
17334
+ export default defineTools([
17329
17335
  {
17330
17336
  name: 'get_current_time',
17331
- description: 'Get the current date and time',
17337
+ description: 'Get the current date and time in a specific timezone',
17332
17338
  parameters: {
17333
17339
  type: 'object',
17334
17340
  properties: {
@@ -17338,19 +17344,59 @@ export const tools = defineTools([
17338
17344
  },
17339
17345
  },
17340
17346
  },
17341
- handler: async (params) => {
17342
- const timezone = (params.timezone as string) || 'UTC'
17347
+ handler: async (args, context, fetch) => {
17348
+ const timezone = (args.timezone as string) || 'UTC'
17343
17349
  const now = new Date()
17344
17350
  return {
17345
17351
  timestamp: now.toISOString(),
17346
17352
  formatted: now.toLocaleString('en-US', { timeZone: timezone }),
17347
17353
  timezone,
17354
+ organizationId: context.organizationId,
17348
17355
  }
17349
17356
  },
17350
17357
  },
17351
- ])
17352
17358
 
17353
- export default tools
17359
+ {
17360
+ name: 'send_slack_message',
17361
+ description: 'Send a message to a Slack channel via webhook',
17362
+ parameters: {
17363
+ type: 'object',
17364
+ properties: {
17365
+ message: {
17366
+ type: 'string',
17367
+ description: 'The message to send',
17368
+ },
17369
+ channel: {
17370
+ type: 'string',
17371
+ description: 'Channel name (for logging purposes)',
17372
+ },
17373
+ },
17374
+ required: ['message'],
17375
+ },
17376
+ handler: async (args, context, fetch) => {
17377
+ const webhookUrl = process.env.SLACK_WEBHOOK_URL
17378
+ if (!webhookUrl) {
17379
+ return { success: false, error: 'SLACK_WEBHOOK_URL not configured' }
17380
+ }
17381
+
17382
+ const response = await fetch(webhookUrl, {
17383
+ method: 'POST',
17384
+ headers: { 'Content-Type': 'application/json' },
17385
+ body: JSON.stringify({
17386
+ text: args.message,
17387
+ username: 'Struere Agent',
17388
+ }),
17389
+ })
17390
+
17391
+ return {
17392
+ success: response.ok,
17393
+ status: response.status,
17394
+ actorId: context.actorId,
17395
+ actorType: context.actorType,
17396
+ }
17397
+ },
17398
+ },
17399
+ ])
17354
17400
  `;
17355
17401
  }
17356
17402
  function getStruereJsonV2(orgId, orgSlug, orgName) {
@@ -17384,123 +17430,430 @@ function getPackageJsonV2(name) {
17384
17430
  }, null, 2);
17385
17431
  }
17386
17432
  function getClaudeMDV2(orgName) {
17387
- return `# ${orgName} - Struere Project
17433
+ return `# ${orgName} - Struere Workspace
17434
+
17435
+ > **This is a workspace project**, not the Struere framework source code. You define agents, entity types, roles, and custom tools here. The CLI syncs them to Convex. Framework source: github.com/struere/struere
17436
+
17437
+ Struere is a framework for building production AI agents with Convex as the real-time backend. Agents can manage entities (business data), emit events, and schedule background jobs\u2014all with built-in RBAC permissions.
17388
17438
 
17389
- This is a Struere organization project. Struere is a framework for building production AI agents with built-in data management, RBAC permissions, and job scheduling.
17439
+ ## How It Works
17440
+
17441
+ \`\`\`
17442
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
17443
+ \u2502 Your Project (this folder) \u2502
17444
+ \u2502 \u251C\u2500\u2500 agents/*.ts \u2192 Agent configs synced to Convex \u2502
17445
+ \u2502 \u251C\u2500\u2500 entity-types/*.ts \u2192 Schema definitions synced to Convex \u2502
17446
+ \u2502 \u251C\u2500\u2500 roles/*.ts \u2192 RBAC policies synced to Convex \u2502
17447
+ \u2502 \u2514\u2500\u2500 tools/index.ts \u2192 Custom tools (handlers run on CF Worker)\u2502
17448
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
17449
+ \u2502 struere dev (watches & syncs)
17450
+ \u25BC
17451
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
17452
+ \u2502 Convex (Real-time Backend) \u2502
17453
+ \u2502 \u2022 Stores agent configs, entities, events, jobs \u2502
17454
+ \u2502 \u2022 Runs LLM calls (Anthropic/OpenAI) \u2502
17455
+ \u2502 \u2022 Enforces RBAC on every operation \u2502
17456
+ \u2502 \u2022 Executes custom tools via Cloudflare Worker \u2502
17457
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
17458
+ \u2502 HTTP API
17459
+ \u25BC
17460
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
17461
+ \u2502 Clients \u2502
17462
+ \u2502 \u2022 Dashboard (chat UI, entity browser) \u2502
17463
+ \u2502 \u2022 Your app (REST API with Bearer token) \u2502
17464
+ \u2502 \u2022 WhatsApp/Webhooks \u2502
17465
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
17466
+ \`\`\`
17390
17467
 
17391
17468
  ## Project Structure
17392
17469
 
17393
17470
  \`\`\`
17394
- agents/ # Agent definitions
17395
- \u251C\u2500\u2500 scheduler.ts # Example agent
17396
- \u2514\u2500\u2500 index.ts # Re-exports all agents
17471
+ agents/ # Agent definitions (synced to Convex)
17472
+ \u251C\u2500\u2500 my-agent.ts # One file per agent
17473
+ \u2514\u2500\u2500 index.ts # Re-exports (optional)
17397
17474
 
17398
- entity-types/ # Entity type schemas
17399
- \u251C\u2500\u2500 teacher.ts # Example entity type
17400
- \u2514\u2500\u2500 index.ts # Re-exports all entity types
17475
+ entity-types/ # Data schemas (like DB tables)
17476
+ \u251C\u2500\u2500 customer.ts # Defines shape of "customer" entities
17477
+ \u2514\u2500\u2500 index.ts
17401
17478
 
17402
- roles/ # Role + permission definitions
17403
- \u251C\u2500\u2500 admin.ts # Example role with policies
17404
- \u2514\u2500\u2500 index.ts # Re-exports all roles
17479
+ roles/ # RBAC: who can do what
17480
+ \u251C\u2500\u2500 admin.ts # Full access
17481
+ \u251C\u2500\u2500 support.ts # Limited access
17482
+ \u2514\u2500\u2500 index.ts
17405
17483
 
17406
- tools/ # Shared custom tools
17407
- \u2514\u2500\u2500 index.ts # Custom tool definitions
17484
+ tools/ # Custom tools shared by all agents
17485
+ \u2514\u2500\u2500 index.ts # defineTools([...])
17408
17486
 
17409
- struere.json # Organization configuration
17410
- struere.config.ts # Framework settings
17487
+ struere.json # Organization ID (don't edit)
17488
+ struere.config.ts # Local dev settings (port, CORS)
17411
17489
  \`\`\`
17412
17490
 
17413
- ## CLI Commands
17491
+ ## Configuration Files
17414
17492
 
17415
- | Command | Description |
17416
- |---------|-------------|
17417
- | \`struere dev\` | Watch and sync all resources to Convex |
17418
- | \`struere deploy\` | Deploy all agents to production |
17419
- | \`struere add <type> <name>\` | Scaffold new agent/entity-type/role |
17420
- | \`struere status\` | Compare local vs remote state |
17493
+ ### struere.json (auto-generated, don't edit)
17494
+ Links this project to your Convex organization:
17495
+ \`\`\`json
17496
+ {
17497
+ "version": "2.0",
17498
+ "organization": { "id": "org_xxx", "slug": "my-org", "name": "My Org" }
17499
+ }
17500
+ \`\`\`
17421
17501
 
17422
- ## Defining Resources
17502
+ ### struere.config.ts (optional local settings)
17503
+ \`\`\`typescript
17504
+ import { defineConfig } from 'struere'
17505
+ export default defineConfig({
17506
+ port: 3000, // Local dev server port
17507
+ logging: { level: 'debug' }
17508
+ })
17509
+ \`\`\`
17423
17510
 
17424
- ### Agents (\`agents/*.ts\`)
17511
+ ## CLI Commands
17425
17512
 
17513
+ | Command | What it does |
17514
+ |---------|--------------|
17515
+ | \`struere dev\` | Watch files, sync to Convex on every save |
17516
+ | \`struere deploy\` | Copy dev config to production for all agents |
17517
+ | \`struere add agent <name>\` | Create agents/name.ts with template |
17518
+ | \`struere add entity-type <name>\` | Create entity-types/name.ts |
17519
+ | \`struere add role <name>\` | Create roles/name.ts |
17520
+ | \`struere status\` | Show what's synced vs local-only |
17521
+
17522
+ ## Defining Agents
17523
+
17524
+ Create \`agents/support.ts\`:
17426
17525
  \`\`\`typescript
17427
17526
  import { defineAgent } from 'struere'
17428
17527
 
17429
17528
  export default defineAgent({
17430
- name: "Scheduler",
17431
- slug: "scheduler",
17529
+ name: "Support Agent",
17530
+ slug: "support",
17432
17531
  version: "0.1.0",
17433
- systemPrompt: "You are a scheduling assistant...",
17434
- model: { provider: "anthropic", name: "claude-sonnet-4-20250514" },
17435
- tools: ["entity.create", "entity.query", "event.emit"],
17532
+ model: {
17533
+ provider: "anthropic", // or "openai", "google"
17534
+ name: "claude-sonnet-4-20250514",
17535
+ temperature: 0.7,
17536
+ maxTokens: 4096,
17537
+ },
17538
+ systemPrompt: \\\`You are a support agent for {{organizationName}}.
17539
+ Current time: {{currentTime}}
17540
+
17541
+ Available customers:
17542
+ {{#each entityTypes}}
17543
+ - {{this.name}}: {{this.description}}
17544
+ {{/each}}
17545
+
17546
+ Use entity.query to look up customer info before responding.\\\`,
17547
+ tools: [
17548
+ "entity.query",
17549
+ "entity.get",
17550
+ "entity.update",
17551
+ "event.emit",
17552
+ "send_email", // custom tool from tools/index.ts
17553
+ ],
17436
17554
  })
17437
17555
  \`\`\`
17438
17556
 
17439
- ### Entity Types (\`entity-types/*.ts\`)
17557
+ ### System Prompt Variables
17558
+
17559
+ | Variable | Value |
17560
+ |----------|-------|
17561
+ | \`{{currentTime}}\` | ISO 8601 timestamp |
17562
+ | \`{{organizationName}}\` | Your org name |
17563
+ | \`{{agentName}}\` | This agent's name |
17564
+ | \`{{entityTypes}}\` | Array of all entity types (for #each loops) |
17565
+ | \`{{roles}}\` | Array of all roles |
17566
+
17567
+ ## Defining Entity Types
17440
17568
 
17569
+ Create \`entity-types/customer.ts\`:
17441
17570
  \`\`\`typescript
17442
17571
  import { defineEntityType } from 'struere'
17443
17572
 
17444
17573
  export default defineEntityType({
17445
- name: "Teacher",
17446
- slug: "teacher",
17574
+ name: "Customer",
17575
+ slug: "customer",
17447
17576
  schema: {
17448
17577
  type: "object",
17449
17578
  properties: {
17450
17579
  name: { type: "string" },
17451
17580
  email: { type: "string", format: "email" },
17452
- hourlyRate: { type: "number" },
17581
+ plan: { type: "string", enum: ["free", "pro", "enterprise"] },
17582
+ metadata: { type: "object" },
17453
17583
  },
17454
17584
  required: ["name", "email"],
17455
17585
  },
17456
- searchFields: ["name", "email"],
17586
+ searchFields: ["name", "email"], // Fields indexed for search
17457
17587
  })
17458
17588
  \`\`\`
17459
17589
 
17460
- ### Roles (\`roles/*.ts\`)
17590
+ Entities are stored as:
17591
+ \`\`\`json
17592
+ {
17593
+ "_id": "ent_abc123",
17594
+ "type": "customer",
17595
+ "data": { "name": "John", "email": "john@example.com", "plan": "pro" },
17596
+ "status": "active",
17597
+ "createdAt": 1706745600000
17598
+ }
17599
+ \`\`\`
17600
+
17601
+ ## Defining Roles (RBAC)
17461
17602
 
17603
+ Create \`roles/support.ts\`:
17462
17604
  \`\`\`typescript
17463
17605
  import { defineRole } from 'struere'
17464
17606
 
17465
17607
  export default defineRole({
17466
- name: "teacher",
17467
- description: "Tutors who conduct sessions",
17608
+ name: "support",
17609
+ description: "Support staff with limited access",
17610
+
17611
+ // What actions are allowed/denied
17468
17612
  policies: [
17469
- { resource: "session", actions: ["list", "read", "update"], effect: "allow", priority: 50 },
17613
+ { resource: "customer", actions: ["list", "read"], effect: "allow", priority: 50 },
17614
+ { resource: "customer", actions: ["delete"], effect: "deny", priority: 100 },
17470
17615
  { resource: "payment", actions: ["*"], effect: "deny", priority: 100 },
17471
17616
  ],
17617
+
17618
+ // Row-level security: only see assigned customers
17472
17619
  scopeRules: [
17473
- { entityType: "session", field: "data.teacherId", operator: "eq", value: "actor.userId" },
17620
+ {
17621
+ entityType: "customer",
17622
+ field: "data.assignedTo", // Field in entity data
17623
+ operator: "eq",
17624
+ value: "actor.userId" // Current user's ID
17625
+ },
17474
17626
  ],
17627
+
17628
+ // Column-level security: hide sensitive fields
17475
17629
  fieldMasks: [
17476
- { entityType: "session", fieldPath: "data.paymentId", maskType: "hide" },
17630
+ { entityType: "customer", fieldPath: "data.ssn", maskType: "hide" },
17631
+ { entityType: "customer", fieldPath: "data.creditCard", maskType: "redact" },
17477
17632
  ],
17478
17633
  })
17479
17634
  \`\`\`
17480
17635
 
17481
- ## Built-in Tools
17482
-
17483
- | Tool | Description |
17484
- |------|-------------|
17485
- | \`entity.create\` | Create a new entity |
17486
- | \`entity.get\` | Get entity by ID |
17487
- | \`entity.query\` | Query entities by type/filters |
17488
- | \`entity.update\` | Update entity data |
17489
- | \`entity.delete\` | Soft-delete entity |
17490
- | \`entity.link\` | Create entity relation |
17491
- | \`entity.unlink\` | Remove entity relation |
17492
- | \`event.emit\` | Emit custom event |
17493
- | \`event.query\` | Query events |
17494
- | \`job.enqueue\` | Schedule background job |
17495
- | \`job.status\` | Get job status |
17636
+ ### RBAC Enforcement
17637
+
17638
+ Every tool call goes through permission checks:
17639
+ 1. **Policy check**: Does this role allow the action on this resource?
17640
+ 2. **Scope filter**: Query results filtered to rows user can access
17641
+ 3. **Field mask**: Sensitive fields hidden/redacted in response
17642
+
17643
+ Deny policies override allow. Higher priority wins.
17644
+
17645
+ ## Defining Custom Tools
17646
+
17647
+ Edit \`tools/index.ts\`:
17648
+ \`\`\`typescript
17649
+ import { defineTools } from 'struere'
17650
+
17651
+ export default defineTools([
17652
+ {
17653
+ name: "send_email",
17654
+ description: "Send an email to a recipient",
17655
+ parameters: {
17656
+ type: "object",
17657
+ properties: {
17658
+ to: { type: "string", description: "Recipient email" },
17659
+ subject: { type: "string", description: "Email subject" },
17660
+ body: { type: "string", description: "Email body" },
17661
+ },
17662
+ required: ["to", "subject", "body"],
17663
+ },
17664
+ // Handler runs on Cloudflare Worker (sandboxed)
17665
+ handler: async (args, context, fetch) => {
17666
+ // context = { organizationId, actorId, actorType }
17667
+ // fetch = sandboxed fetch (limited domains)
17668
+
17669
+ const response = await fetch("https://api.sendgrid.com/v3/mail/send", {
17670
+ method: "POST",
17671
+ headers: {
17672
+ "Authorization": \\\`Bearer \\\${process.env.SENDGRID_API_KEY}\\\`,
17673
+ "Content-Type": "application/json",
17674
+ },
17675
+ body: JSON.stringify({
17676
+ personalizations: [{ to: [{ email: args.to }] }],
17677
+ from: { email: "noreply@example.com" },
17678
+ subject: args.subject,
17679
+ content: [{ type: "text/plain", value: args.body }],
17680
+ }),
17681
+ })
17682
+ return { success: response.ok, status: response.status }
17683
+ },
17684
+ },
17685
+
17686
+ {
17687
+ name: "lookup_order",
17688
+ description: "Look up order by ID",
17689
+ parameters: {
17690
+ type: "object",
17691
+ properties: {
17692
+ orderId: { type: "string", description: "Order ID" },
17693
+ },
17694
+ required: ["orderId"],
17695
+ },
17696
+ handler: async (args, context, fetch) => {
17697
+ const res = await fetch(\\\`https://api.myshop.com/orders/\\\${args.orderId}\\\`, {
17698
+ headers: { "X-Org-Id": context.organizationId },
17699
+ })
17700
+ return await res.json()
17701
+ },
17702
+ },
17703
+ ])
17704
+ \`\`\`
17705
+
17706
+ ### Allowed Domains for Custom Tools
17707
+
17708
+ Custom tool handlers can only fetch from:
17709
+ - api.openai.com, api.anthropic.com
17710
+ - api.stripe.com, api.sendgrid.com, api.twilio.com
17711
+ - hooks.slack.com, discord.com, api.github.com
17712
+
17713
+ ## Built-in Tools Reference
17714
+
17715
+ ### Entity Tools
17716
+
17717
+ \`\`\`typescript
17718
+ // entity.create - Create new entity
17719
+ { type: "customer", data: { name: "John", email: "j@example.com" }, status: "active" }
17720
+
17721
+ // entity.get - Get by ID
17722
+ { id: "ent_abc123" }
17723
+
17724
+ // entity.query - Search/filter
17725
+ { type: "customer", filters: { "data.plan": "pro" }, status: "active", limit: 50 }
17726
+
17727
+ // entity.update - Partial update
17728
+ { id: "ent_abc123", data: { plan: "enterprise" } }
17729
+
17730
+ // entity.delete - Soft delete
17731
+ { id: "ent_abc123" }
17732
+
17733
+ // entity.link - Create relation
17734
+ { fromEntityId: "ent_abc", toEntityId: "ent_xyz", relationType: "assigned_to" }
17735
+
17736
+ // entity.unlink - Remove relation
17737
+ { fromEntityId: "ent_abc", toEntityId: "ent_xyz", relationType: "assigned_to" }
17738
+ \`\`\`
17739
+
17740
+ ### Event Tools
17741
+
17742
+ \`\`\`typescript
17743
+ // event.emit - Log an event
17744
+ { eventType: "support.ticket.resolved", entityId: "ent_abc", payload: { rating: 5 } }
17745
+
17746
+ // event.query - Query event history
17747
+ { eventType: "support.ticket.*", entityId: "ent_abc", limit: 20 }
17748
+ \`\`\`
17749
+
17750
+ Events are immutable audit logs. Use for analytics, debugging, compliance.
17751
+
17752
+ ### Job Tools
17753
+
17754
+ \`\`\`typescript
17755
+ // job.enqueue - Schedule background work
17756
+ {
17757
+ jobType: "send_reminder",
17758
+ payload: { customerId: "ent_abc", message: "Your trial ends soon" },
17759
+ runAt: 1706832000000 // Unix timestamp (optional, runs immediately if omitted)
17760
+ }
17761
+
17762
+ // job.status - Check job status
17763
+ { jobId: "job_xyz123" }
17764
+ // Returns: { status: "pending" | "running" | "completed" | "failed", result: {...} }
17765
+ \`\`\`
17766
+
17767
+ Jobs run asynchronously with retry logic. Use for: emails, notifications, data sync.
17768
+
17769
+ ## Invoking Agents (API)
17770
+
17771
+ ### Chat Endpoint
17772
+ \`\`\`bash
17773
+ curl -X POST https://your-convex-url.convex.cloud/v1/chat \\
17774
+ -H "Authorization: Bearer sk_live_xxx" \\
17775
+ -H "Content-Type: application/json" \\
17776
+ -d '{
17777
+ "agentId": "agent_abc123",
17778
+ "message": "What is the status of order #12345?",
17779
+ "threadId": "thread_xyz", // optional, creates new if omitted
17780
+ "metadata": { "customerId": "ent_cust_789" } // available in system prompt
17781
+ }'
17782
+ \`\`\`
17783
+
17784
+ ### Response
17785
+ \`\`\`json
17786
+ {
17787
+ "threadId": "thread_xyz",
17788
+ "message": "Order #12345 is currently being shipped...",
17789
+ "usage": { "inputTokens": 150, "outputTokens": 89 }
17790
+ }
17791
+ \`\`\`
17792
+
17793
+ ### By Slug (production)
17794
+ \`\`\`bash
17795
+ curl -X POST https://your-convex-url.convex.cloud/v1/agents/support/chat \\
17796
+ -H "Authorization: Bearer sk_live_xxx" \\
17797
+ -d '{"message": "Hello"}'
17798
+ \`\`\`
17496
17799
 
17497
17800
  ## Development Workflow
17498
17801
 
17499
- 1. Run \`struere dev\` to start watching for changes
17500
- 2. Edit agents, entity types, or roles
17501
- 3. Changes are automatically synced to Convex
17502
- 4. Test via API or dashboard
17503
- 5. Run \`struere deploy\` when ready for production
17802
+ 1. \`struere dev\` - Start watching
17803
+ 2. Edit files in agents/, entity-types/, roles/, tools/
17804
+ 3. Save \u2192 auto-syncs to Convex (you'll see "Synced" message)
17805
+ 4. Test via dashboard or curl
17806
+ 5. \`struere deploy\` - Push to production
17807
+
17808
+ ## Common Patterns
17809
+
17810
+ ### Customer Support Agent
17811
+ \`\`\`typescript
17812
+ // agents/support.ts
17813
+ export default defineAgent({
17814
+ name: "Support",
17815
+ slug: "support",
17816
+ version: "0.1.0",
17817
+ systemPrompt: \\\`You help customers with their orders and account issues.
17818
+
17819
+ When a customer asks about an order, use entity.query to find it first.
17820
+ Always be polite and helpful. If you can't help, offer to escalate.\\\`,
17821
+ model: { provider: "anthropic", name: "claude-sonnet-4-20250514" },
17822
+ tools: ["entity.query", "entity.get", "entity.update", "event.emit"],
17823
+ })
17824
+ \`\`\`
17825
+
17826
+ ### Scheduling Agent
17827
+ \`\`\`typescript
17828
+ // agents/scheduler.ts
17829
+ export default defineAgent({
17830
+ name: "Scheduler",
17831
+ slug: "scheduler",
17832
+ version: "0.1.0",
17833
+ systemPrompt: \\\`You help schedule appointments between teachers and students.
17834
+
17835
+ Check teacher availability before booking. Create session entities for confirmed bookings.
17836
+ Send confirmation via the send_notification custom tool.\\\`,
17837
+ model: { provider: "anthropic", name: "claude-sonnet-4-20250514" },
17838
+ tools: ["entity.create", "entity.query", "job.enqueue", "send_notification"],
17839
+ })
17840
+ \`\`\`
17841
+
17842
+ ### Data Entry Agent
17843
+ \`\`\`typescript
17844
+ // agents/data-entry.ts
17845
+ export default defineAgent({
17846
+ name: "Data Entry",
17847
+ slug: "data-entry",
17848
+ version: "0.1.0",
17849
+ systemPrompt: \\\`You help users create and update records in the system.
17850
+
17851
+ When creating entities, validate the data matches the schema.
17852
+ Always confirm what was created/updated.\\\`,
17853
+ model: { provider: "anthropic", name: "claude-sonnet-4-20250514" },
17854
+ tools: ["entity.create", "entity.update", "entity.query"],
17855
+ })
17856
+ \`\`\`
17504
17857
  `;
17505
17858
  }
17506
17859
 
@@ -18091,7 +18444,9 @@ var devCommand = new Command("dev").description("Sync all resources to developme
18091
18444
  ].filter((p) => existsSync5(p));
18092
18445
  const watcher = import_chokidar.default.watch(watchPaths, {
18093
18446
  ignoreInitial: true,
18094
- ignored: /node_modules/
18447
+ ignored: /node_modules/,
18448
+ persistent: true,
18449
+ usePolling: false
18095
18450
  });
18096
18451
  watcher.on("change", async (path) => {
18097
18452
  const relativePath = path.replace(cwd, ".");
@@ -18147,10 +18502,15 @@ var devCommand = new Command("dev").description("Sync all resources to developme
18147
18502
  console.log(source_default.red("Error:"), error instanceof Error ? error.message : String(error));
18148
18503
  }
18149
18504
  });
18150
- process.on("SIGINT", () => {
18505
+ let isClosing = false;
18506
+ process.on("SIGINT", async () => {
18507
+ if (isClosing) {
18508
+ process.exit(0);
18509
+ }
18510
+ isClosing = true;
18151
18511
  console.log();
18152
- watcher.close();
18153
- console.log(source_default.gray("Stopped"));
18512
+ console.log(source_default.gray("Stopping..."));
18513
+ await watcher.close();
18154
18514
  process.exit(0);
18155
18515
  });
18156
18516
  });
@@ -19100,7 +19460,7 @@ var statusCommand = new Command("status").description("Compare local vs remote s
19100
19460
  // package.json
19101
19461
  var package_default = {
19102
19462
  name: "struere",
19103
- version: "0.4.2",
19463
+ version: "0.4.3",
19104
19464
  description: "Build, test, and deploy AI agents",
19105
19465
  keywords: [
19106
19466
  "ai",
@@ -1 +1 @@
1
- {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAenC,eAAO,MAAM,UAAU,SAqMnB,CAAA"}
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAenC,eAAO,MAAM,UAAU,SA4MnB,CAAA"}
package/dist/cli/index.js CHANGED
@@ -243,8 +243,11 @@ async function syncOrganization(payload) {
243
243
  const error = await response.text();
244
244
  return { success: false, error };
245
245
  }
246
- const result = await response.json();
247
- return result;
246
+ const json = await response.json();
247
+ if (json.status === "success" && json.value) {
248
+ return json.value;
249
+ }
250
+ return { success: false, error: "Unexpected response format" };
248
251
  }
249
252
  async function getSyncState() {
250
253
  const credentials = loadCredentials();
@@ -293,8 +296,11 @@ async function deployAllAgents() {
293
296
  const error = await response.text();
294
297
  return { success: false, error };
295
298
  }
296
- const result = await response.json();
297
- return result;
299
+ const json = await response.json();
300
+ if (json.status === "success" && json.value) {
301
+ return json.value;
302
+ }
303
+ return { success: false, error: "Unexpected response format" };
298
304
  }
299
305
 
300
306
  // src/cli/commands/login.ts
@@ -664,10 +670,10 @@ function getIndexTs(type) {
664
670
  function getToolsIndexTs() {
665
671
  return `import { defineTools } from 'struere'
666
672
 
667
- export const tools = defineTools([
673
+ export default defineTools([
668
674
  {
669
675
  name: 'get_current_time',
670
- description: 'Get the current date and time',
676
+ description: 'Get the current date and time in a specific timezone',
671
677
  parameters: {
672
678
  type: 'object',
673
679
  properties: {
@@ -677,19 +683,59 @@ export const tools = defineTools([
677
683
  },
678
684
  },
679
685
  },
680
- handler: async (params) => {
681
- const timezone = (params.timezone as string) || 'UTC'
686
+ handler: async (args, context, fetch) => {
687
+ const timezone = (args.timezone as string) || 'UTC'
682
688
  const now = new Date()
683
689
  return {
684
690
  timestamp: now.toISOString(),
685
691
  formatted: now.toLocaleString('en-US', { timeZone: timezone }),
686
692
  timezone,
693
+ organizationId: context.organizationId,
687
694
  }
688
695
  },
689
696
  },
690
- ])
691
697
 
692
- export default tools
698
+ {
699
+ name: 'send_slack_message',
700
+ description: 'Send a message to a Slack channel via webhook',
701
+ parameters: {
702
+ type: 'object',
703
+ properties: {
704
+ message: {
705
+ type: 'string',
706
+ description: 'The message to send',
707
+ },
708
+ channel: {
709
+ type: 'string',
710
+ description: 'Channel name (for logging purposes)',
711
+ },
712
+ },
713
+ required: ['message'],
714
+ },
715
+ handler: async (args, context, fetch) => {
716
+ const webhookUrl = process.env.SLACK_WEBHOOK_URL
717
+ if (!webhookUrl) {
718
+ return { success: false, error: 'SLACK_WEBHOOK_URL not configured' }
719
+ }
720
+
721
+ const response = await fetch(webhookUrl, {
722
+ method: 'POST',
723
+ headers: { 'Content-Type': 'application/json' },
724
+ body: JSON.stringify({
725
+ text: args.message,
726
+ username: 'Struere Agent',
727
+ }),
728
+ })
729
+
730
+ return {
731
+ success: response.ok,
732
+ status: response.status,
733
+ actorId: context.actorId,
734
+ actorType: context.actorType,
735
+ }
736
+ },
737
+ },
738
+ ])
693
739
  `;
694
740
  }
695
741
  function getStruereJsonV2(orgId, orgSlug, orgName) {
@@ -723,123 +769,430 @@ function getPackageJsonV2(name) {
723
769
  }, null, 2);
724
770
  }
725
771
  function getClaudeMDV2(orgName) {
726
- return `# ${orgName} - Struere Project
772
+ return `# ${orgName} - Struere Workspace
773
+
774
+ > **This is a workspace project**, not the Struere framework source code. You define agents, entity types, roles, and custom tools here. The CLI syncs them to Convex. Framework source: github.com/struere/struere
775
+
776
+ Struere is a framework for building production AI agents with Convex as the real-time backend. Agents can manage entities (business data), emit events, and schedule background jobs\u2014all with built-in RBAC permissions.
727
777
 
728
- This is a Struere organization project. Struere is a framework for building production AI agents with built-in data management, RBAC permissions, and job scheduling.
778
+ ## How It Works
779
+
780
+ \`\`\`
781
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
782
+ \u2502 Your Project (this folder) \u2502
783
+ \u2502 \u251C\u2500\u2500 agents/*.ts \u2192 Agent configs synced to Convex \u2502
784
+ \u2502 \u251C\u2500\u2500 entity-types/*.ts \u2192 Schema definitions synced to Convex \u2502
785
+ \u2502 \u251C\u2500\u2500 roles/*.ts \u2192 RBAC policies synced to Convex \u2502
786
+ \u2502 \u2514\u2500\u2500 tools/index.ts \u2192 Custom tools (handlers run on CF Worker)\u2502
787
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
788
+ \u2502 struere dev (watches & syncs)
789
+ \u25BC
790
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
791
+ \u2502 Convex (Real-time Backend) \u2502
792
+ \u2502 \u2022 Stores agent configs, entities, events, jobs \u2502
793
+ \u2502 \u2022 Runs LLM calls (Anthropic/OpenAI) \u2502
794
+ \u2502 \u2022 Enforces RBAC on every operation \u2502
795
+ \u2502 \u2022 Executes custom tools via Cloudflare Worker \u2502
796
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
797
+ \u2502 HTTP API
798
+ \u25BC
799
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
800
+ \u2502 Clients \u2502
801
+ \u2502 \u2022 Dashboard (chat UI, entity browser) \u2502
802
+ \u2502 \u2022 Your app (REST API with Bearer token) \u2502
803
+ \u2502 \u2022 WhatsApp/Webhooks \u2502
804
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
805
+ \`\`\`
729
806
 
730
807
  ## Project Structure
731
808
 
732
809
  \`\`\`
733
- agents/ # Agent definitions
734
- \u251C\u2500\u2500 scheduler.ts # Example agent
735
- \u2514\u2500\u2500 index.ts # Re-exports all agents
810
+ agents/ # Agent definitions (synced to Convex)
811
+ \u251C\u2500\u2500 my-agent.ts # One file per agent
812
+ \u2514\u2500\u2500 index.ts # Re-exports (optional)
736
813
 
737
- entity-types/ # Entity type schemas
738
- \u251C\u2500\u2500 teacher.ts # Example entity type
739
- \u2514\u2500\u2500 index.ts # Re-exports all entity types
814
+ entity-types/ # Data schemas (like DB tables)
815
+ \u251C\u2500\u2500 customer.ts # Defines shape of "customer" entities
816
+ \u2514\u2500\u2500 index.ts
740
817
 
741
- roles/ # Role + permission definitions
742
- \u251C\u2500\u2500 admin.ts # Example role with policies
743
- \u2514\u2500\u2500 index.ts # Re-exports all roles
818
+ roles/ # RBAC: who can do what
819
+ \u251C\u2500\u2500 admin.ts # Full access
820
+ \u251C\u2500\u2500 support.ts # Limited access
821
+ \u2514\u2500\u2500 index.ts
744
822
 
745
- tools/ # Shared custom tools
746
- \u2514\u2500\u2500 index.ts # Custom tool definitions
823
+ tools/ # Custom tools shared by all agents
824
+ \u2514\u2500\u2500 index.ts # defineTools([...])
747
825
 
748
- struere.json # Organization configuration
749
- struere.config.ts # Framework settings
826
+ struere.json # Organization ID (don't edit)
827
+ struere.config.ts # Local dev settings (port, CORS)
750
828
  \`\`\`
751
829
 
752
- ## CLI Commands
830
+ ## Configuration Files
831
+
832
+ ### struere.json (auto-generated, don't edit)
833
+ Links this project to your Convex organization:
834
+ \`\`\`json
835
+ {
836
+ "version": "2.0",
837
+ "organization": { "id": "org_xxx", "slug": "my-org", "name": "My Org" }
838
+ }
839
+ \`\`\`
840
+
841
+ ### struere.config.ts (optional local settings)
842
+ \`\`\`typescript
843
+ import { defineConfig } from 'struere'
844
+ export default defineConfig({
845
+ port: 3000, // Local dev server port
846
+ logging: { level: 'debug' }
847
+ })
848
+ \`\`\`
753
849
 
754
- | Command | Description |
755
- |---------|-------------|
756
- | \`struere dev\` | Watch and sync all resources to Convex |
757
- | \`struere deploy\` | Deploy all agents to production |
758
- | \`struere add <type> <name>\` | Scaffold new agent/entity-type/role |
759
- | \`struere status\` | Compare local vs remote state |
850
+ ## CLI Commands
760
851
 
761
- ## Defining Resources
852
+ | Command | What it does |
853
+ |---------|--------------|
854
+ | \`struere dev\` | Watch files, sync to Convex on every save |
855
+ | \`struere deploy\` | Copy dev config to production for all agents |
856
+ | \`struere add agent <name>\` | Create agents/name.ts with template |
857
+ | \`struere add entity-type <name>\` | Create entity-types/name.ts |
858
+ | \`struere add role <name>\` | Create roles/name.ts |
859
+ | \`struere status\` | Show what's synced vs local-only |
762
860
 
763
- ### Agents (\`agents/*.ts\`)
861
+ ## Defining Agents
764
862
 
863
+ Create \`agents/support.ts\`:
765
864
  \`\`\`typescript
766
865
  import { defineAgent } from 'struere'
767
866
 
768
867
  export default defineAgent({
769
- name: "Scheduler",
770
- slug: "scheduler",
868
+ name: "Support Agent",
869
+ slug: "support",
771
870
  version: "0.1.0",
772
- systemPrompt: "You are a scheduling assistant...",
773
- model: { provider: "anthropic", name: "claude-sonnet-4-20250514" },
774
- tools: ["entity.create", "entity.query", "event.emit"],
871
+ model: {
872
+ provider: "anthropic", // or "openai", "google"
873
+ name: "claude-sonnet-4-20250514",
874
+ temperature: 0.7,
875
+ maxTokens: 4096,
876
+ },
877
+ systemPrompt: \\\`You are a support agent for {{organizationName}}.
878
+ Current time: {{currentTime}}
879
+
880
+ Available customers:
881
+ {{#each entityTypes}}
882
+ - {{this.name}}: {{this.description}}
883
+ {{/each}}
884
+
885
+ Use entity.query to look up customer info before responding.\\\`,
886
+ tools: [
887
+ "entity.query",
888
+ "entity.get",
889
+ "entity.update",
890
+ "event.emit",
891
+ "send_email", // custom tool from tools/index.ts
892
+ ],
775
893
  })
776
894
  \`\`\`
777
895
 
778
- ### Entity Types (\`entity-types/*.ts\`)
896
+ ### System Prompt Variables
897
+
898
+ | Variable | Value |
899
+ |----------|-------|
900
+ | \`{{currentTime}}\` | ISO 8601 timestamp |
901
+ | \`{{organizationName}}\` | Your org name |
902
+ | \`{{agentName}}\` | This agent's name |
903
+ | \`{{entityTypes}}\` | Array of all entity types (for #each loops) |
904
+ | \`{{roles}}\` | Array of all roles |
779
905
 
906
+ ## Defining Entity Types
907
+
908
+ Create \`entity-types/customer.ts\`:
780
909
  \`\`\`typescript
781
910
  import { defineEntityType } from 'struere'
782
911
 
783
912
  export default defineEntityType({
784
- name: "Teacher",
785
- slug: "teacher",
913
+ name: "Customer",
914
+ slug: "customer",
786
915
  schema: {
787
916
  type: "object",
788
917
  properties: {
789
918
  name: { type: "string" },
790
919
  email: { type: "string", format: "email" },
791
- hourlyRate: { type: "number" },
920
+ plan: { type: "string", enum: ["free", "pro", "enterprise"] },
921
+ metadata: { type: "object" },
792
922
  },
793
923
  required: ["name", "email"],
794
924
  },
795
- searchFields: ["name", "email"],
925
+ searchFields: ["name", "email"], // Fields indexed for search
796
926
  })
797
927
  \`\`\`
798
928
 
799
- ### Roles (\`roles/*.ts\`)
929
+ Entities are stored as:
930
+ \`\`\`json
931
+ {
932
+ "_id": "ent_abc123",
933
+ "type": "customer",
934
+ "data": { "name": "John", "email": "john@example.com", "plan": "pro" },
935
+ "status": "active",
936
+ "createdAt": 1706745600000
937
+ }
938
+ \`\`\`
939
+
940
+ ## Defining Roles (RBAC)
800
941
 
942
+ Create \`roles/support.ts\`:
801
943
  \`\`\`typescript
802
944
  import { defineRole } from 'struere'
803
945
 
804
946
  export default defineRole({
805
- name: "teacher",
806
- description: "Tutors who conduct sessions",
947
+ name: "support",
948
+ description: "Support staff with limited access",
949
+
950
+ // What actions are allowed/denied
807
951
  policies: [
808
- { resource: "session", actions: ["list", "read", "update"], effect: "allow", priority: 50 },
952
+ { resource: "customer", actions: ["list", "read"], effect: "allow", priority: 50 },
953
+ { resource: "customer", actions: ["delete"], effect: "deny", priority: 100 },
809
954
  { resource: "payment", actions: ["*"], effect: "deny", priority: 100 },
810
955
  ],
956
+
957
+ // Row-level security: only see assigned customers
811
958
  scopeRules: [
812
- { entityType: "session", field: "data.teacherId", operator: "eq", value: "actor.userId" },
959
+ {
960
+ entityType: "customer",
961
+ field: "data.assignedTo", // Field in entity data
962
+ operator: "eq",
963
+ value: "actor.userId" // Current user's ID
964
+ },
813
965
  ],
966
+
967
+ // Column-level security: hide sensitive fields
814
968
  fieldMasks: [
815
- { entityType: "session", fieldPath: "data.paymentId", maskType: "hide" },
969
+ { entityType: "customer", fieldPath: "data.ssn", maskType: "hide" },
970
+ { entityType: "customer", fieldPath: "data.creditCard", maskType: "redact" },
816
971
  ],
817
972
  })
818
973
  \`\`\`
819
974
 
820
- ## Built-in Tools
821
-
822
- | Tool | Description |
823
- |------|-------------|
824
- | \`entity.create\` | Create a new entity |
825
- | \`entity.get\` | Get entity by ID |
826
- | \`entity.query\` | Query entities by type/filters |
827
- | \`entity.update\` | Update entity data |
828
- | \`entity.delete\` | Soft-delete entity |
829
- | \`entity.link\` | Create entity relation |
830
- | \`entity.unlink\` | Remove entity relation |
831
- | \`event.emit\` | Emit custom event |
832
- | \`event.query\` | Query events |
833
- | \`job.enqueue\` | Schedule background job |
834
- | \`job.status\` | Get job status |
975
+ ### RBAC Enforcement
976
+
977
+ Every tool call goes through permission checks:
978
+ 1. **Policy check**: Does this role allow the action on this resource?
979
+ 2. **Scope filter**: Query results filtered to rows user can access
980
+ 3. **Field mask**: Sensitive fields hidden/redacted in response
981
+
982
+ Deny policies override allow. Higher priority wins.
983
+
984
+ ## Defining Custom Tools
985
+
986
+ Edit \`tools/index.ts\`:
987
+ \`\`\`typescript
988
+ import { defineTools } from 'struere'
989
+
990
+ export default defineTools([
991
+ {
992
+ name: "send_email",
993
+ description: "Send an email to a recipient",
994
+ parameters: {
995
+ type: "object",
996
+ properties: {
997
+ to: { type: "string", description: "Recipient email" },
998
+ subject: { type: "string", description: "Email subject" },
999
+ body: { type: "string", description: "Email body" },
1000
+ },
1001
+ required: ["to", "subject", "body"],
1002
+ },
1003
+ // Handler runs on Cloudflare Worker (sandboxed)
1004
+ handler: async (args, context, fetch) => {
1005
+ // context = { organizationId, actorId, actorType }
1006
+ // fetch = sandboxed fetch (limited domains)
1007
+
1008
+ const response = await fetch("https://api.sendgrid.com/v3/mail/send", {
1009
+ method: "POST",
1010
+ headers: {
1011
+ "Authorization": \\\`Bearer \\\${process.env.SENDGRID_API_KEY}\\\`,
1012
+ "Content-Type": "application/json",
1013
+ },
1014
+ body: JSON.stringify({
1015
+ personalizations: [{ to: [{ email: args.to }] }],
1016
+ from: { email: "noreply@example.com" },
1017
+ subject: args.subject,
1018
+ content: [{ type: "text/plain", value: args.body }],
1019
+ }),
1020
+ })
1021
+ return { success: response.ok, status: response.status }
1022
+ },
1023
+ },
1024
+
1025
+ {
1026
+ name: "lookup_order",
1027
+ description: "Look up order by ID",
1028
+ parameters: {
1029
+ type: "object",
1030
+ properties: {
1031
+ orderId: { type: "string", description: "Order ID" },
1032
+ },
1033
+ required: ["orderId"],
1034
+ },
1035
+ handler: async (args, context, fetch) => {
1036
+ const res = await fetch(\\\`https://api.myshop.com/orders/\\\${args.orderId}\\\`, {
1037
+ headers: { "X-Org-Id": context.organizationId },
1038
+ })
1039
+ return await res.json()
1040
+ },
1041
+ },
1042
+ ])
1043
+ \`\`\`
1044
+
1045
+ ### Allowed Domains for Custom Tools
1046
+
1047
+ Custom tool handlers can only fetch from:
1048
+ - api.openai.com, api.anthropic.com
1049
+ - api.stripe.com, api.sendgrid.com, api.twilio.com
1050
+ - hooks.slack.com, discord.com, api.github.com
1051
+
1052
+ ## Built-in Tools Reference
1053
+
1054
+ ### Entity Tools
1055
+
1056
+ \`\`\`typescript
1057
+ // entity.create - Create new entity
1058
+ { type: "customer", data: { name: "John", email: "j@example.com" }, status: "active" }
1059
+
1060
+ // entity.get - Get by ID
1061
+ { id: "ent_abc123" }
1062
+
1063
+ // entity.query - Search/filter
1064
+ { type: "customer", filters: { "data.plan": "pro" }, status: "active", limit: 50 }
1065
+
1066
+ // entity.update - Partial update
1067
+ { id: "ent_abc123", data: { plan: "enterprise" } }
1068
+
1069
+ // entity.delete - Soft delete
1070
+ { id: "ent_abc123" }
1071
+
1072
+ // entity.link - Create relation
1073
+ { fromEntityId: "ent_abc", toEntityId: "ent_xyz", relationType: "assigned_to" }
1074
+
1075
+ // entity.unlink - Remove relation
1076
+ { fromEntityId: "ent_abc", toEntityId: "ent_xyz", relationType: "assigned_to" }
1077
+ \`\`\`
1078
+
1079
+ ### Event Tools
1080
+
1081
+ \`\`\`typescript
1082
+ // event.emit - Log an event
1083
+ { eventType: "support.ticket.resolved", entityId: "ent_abc", payload: { rating: 5 } }
1084
+
1085
+ // event.query - Query event history
1086
+ { eventType: "support.ticket.*", entityId: "ent_abc", limit: 20 }
1087
+ \`\`\`
1088
+
1089
+ Events are immutable audit logs. Use for analytics, debugging, compliance.
1090
+
1091
+ ### Job Tools
1092
+
1093
+ \`\`\`typescript
1094
+ // job.enqueue - Schedule background work
1095
+ {
1096
+ jobType: "send_reminder",
1097
+ payload: { customerId: "ent_abc", message: "Your trial ends soon" },
1098
+ runAt: 1706832000000 // Unix timestamp (optional, runs immediately if omitted)
1099
+ }
1100
+
1101
+ // job.status - Check job status
1102
+ { jobId: "job_xyz123" }
1103
+ // Returns: { status: "pending" | "running" | "completed" | "failed", result: {...} }
1104
+ \`\`\`
1105
+
1106
+ Jobs run asynchronously with retry logic. Use for: emails, notifications, data sync.
1107
+
1108
+ ## Invoking Agents (API)
1109
+
1110
+ ### Chat Endpoint
1111
+ \`\`\`bash
1112
+ curl -X POST https://your-convex-url.convex.cloud/v1/chat \\
1113
+ -H "Authorization: Bearer sk_live_xxx" \\
1114
+ -H "Content-Type: application/json" \\
1115
+ -d '{
1116
+ "agentId": "agent_abc123",
1117
+ "message": "What is the status of order #12345?",
1118
+ "threadId": "thread_xyz", // optional, creates new if omitted
1119
+ "metadata": { "customerId": "ent_cust_789" } // available in system prompt
1120
+ }'
1121
+ \`\`\`
1122
+
1123
+ ### Response
1124
+ \`\`\`json
1125
+ {
1126
+ "threadId": "thread_xyz",
1127
+ "message": "Order #12345 is currently being shipped...",
1128
+ "usage": { "inputTokens": 150, "outputTokens": 89 }
1129
+ }
1130
+ \`\`\`
1131
+
1132
+ ### By Slug (production)
1133
+ \`\`\`bash
1134
+ curl -X POST https://your-convex-url.convex.cloud/v1/agents/support/chat \\
1135
+ -H "Authorization: Bearer sk_live_xxx" \\
1136
+ -d '{"message": "Hello"}'
1137
+ \`\`\`
835
1138
 
836
1139
  ## Development Workflow
837
1140
 
838
- 1. Run \`struere dev\` to start watching for changes
839
- 2. Edit agents, entity types, or roles
840
- 3. Changes are automatically synced to Convex
841
- 4. Test via API or dashboard
842
- 5. Run \`struere deploy\` when ready for production
1141
+ 1. \`struere dev\` - Start watching
1142
+ 2. Edit files in agents/, entity-types/, roles/, tools/
1143
+ 3. Save \u2192 auto-syncs to Convex (you'll see "Synced" message)
1144
+ 4. Test via dashboard or curl
1145
+ 5. \`struere deploy\` - Push to production
1146
+
1147
+ ## Common Patterns
1148
+
1149
+ ### Customer Support Agent
1150
+ \`\`\`typescript
1151
+ // agents/support.ts
1152
+ export default defineAgent({
1153
+ name: "Support",
1154
+ slug: "support",
1155
+ version: "0.1.0",
1156
+ systemPrompt: \\\`You help customers with their orders and account issues.
1157
+
1158
+ When a customer asks about an order, use entity.query to find it first.
1159
+ Always be polite and helpful. If you can't help, offer to escalate.\\\`,
1160
+ model: { provider: "anthropic", name: "claude-sonnet-4-20250514" },
1161
+ tools: ["entity.query", "entity.get", "entity.update", "event.emit"],
1162
+ })
1163
+ \`\`\`
1164
+
1165
+ ### Scheduling Agent
1166
+ \`\`\`typescript
1167
+ // agents/scheduler.ts
1168
+ export default defineAgent({
1169
+ name: "Scheduler",
1170
+ slug: "scheduler",
1171
+ version: "0.1.0",
1172
+ systemPrompt: \\\`You help schedule appointments between teachers and students.
1173
+
1174
+ Check teacher availability before booking. Create session entities for confirmed bookings.
1175
+ Send confirmation via the send_notification custom tool.\\\`,
1176
+ model: { provider: "anthropic", name: "claude-sonnet-4-20250514" },
1177
+ tools: ["entity.create", "entity.query", "job.enqueue", "send_notification"],
1178
+ })
1179
+ \`\`\`
1180
+
1181
+ ### Data Entry Agent
1182
+ \`\`\`typescript
1183
+ // agents/data-entry.ts
1184
+ export default defineAgent({
1185
+ name: "Data Entry",
1186
+ slug: "data-entry",
1187
+ version: "0.1.0",
1188
+ systemPrompt: \\\`You help users create and update records in the system.
1189
+
1190
+ When creating entities, validate the data matches the schema.
1191
+ Always confirm what was created/updated.\\\`,
1192
+ model: { provider: "anthropic", name: "claude-sonnet-4-20250514" },
1193
+ tools: ["entity.create", "entity.update", "entity.query"],
1194
+ })
1195
+ \`\`\`
843
1196
  `;
844
1197
  }
845
1198
 
@@ -1433,7 +1786,9 @@ var devCommand = new Command3("dev").description("Sync all resources to developm
1433
1786
  ].filter((p) => existsSync5(p));
1434
1787
  const watcher = chokidar.watch(watchPaths, {
1435
1788
  ignoreInitial: true,
1436
- ignored: /node_modules/
1789
+ ignored: /node_modules/,
1790
+ persistent: true,
1791
+ usePolling: false
1437
1792
  });
1438
1793
  watcher.on("change", async (path) => {
1439
1794
  const relativePath = path.replace(cwd, ".");
@@ -1489,10 +1844,15 @@ var devCommand = new Command3("dev").description("Sync all resources to developm
1489
1844
  console.log(chalk3.red("Error:"), error instanceof Error ? error.message : String(error));
1490
1845
  }
1491
1846
  });
1492
- process.on("SIGINT", () => {
1847
+ let isClosing = false;
1848
+ process.on("SIGINT", async () => {
1849
+ if (isClosing) {
1850
+ process.exit(0);
1851
+ }
1852
+ isClosing = true;
1493
1853
  console.log();
1494
- watcher.close();
1495
- console.log(chalk3.gray("Stopped"));
1854
+ console.log(chalk3.gray("Stopping..."));
1855
+ await watcher.close();
1496
1856
  process.exit(0);
1497
1857
  });
1498
1858
  });
@@ -2470,7 +2830,7 @@ var statusCommand = new Command13("status").description("Compare local vs remote
2470
2830
  // package.json
2471
2831
  var package_default = {
2472
2832
  name: "struere",
2473
- version: "0.4.2",
2833
+ version: "0.4.3",
2474
2834
  description: "Build, test, and deploy AI agents",
2475
2835
  keywords: [
2476
2836
  "ai",
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/templates/index.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBnD;AAED,wBAAgB,WAAW,IAAI,MAAM,CAsBpC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAgBzC;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgC/C;AAED,wBAAgB,UAAU,IAAI,MAAM,CAoDnC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAmBzC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAatC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAgBrC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAahG;AAED,wBAAgB,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBlE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAa9C;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAgC/D;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,cAAc,GAAG,OAAO,GAAG,MAAM,CAI5E;AAED,wBAAgB,eAAe,IAAI,MAAM,CA8BxC;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAaxF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBrD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAuHrD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuShD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/templates/index.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBnD;AAED,wBAAgB,WAAW,IAAI,MAAM,CAsBpC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAgBzC;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgC/C;AAED,wBAAgB,UAAU,IAAI,MAAM,CAoDnC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAmBzC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAatC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAgBrC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAahG;AAED,wBAAgB,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBlE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAa9C;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAgC/D;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,cAAc,GAAG,OAAO,GAAG,MAAM,CAI5E;AAED,wBAAgB,eAAe,IAAI,MAAM,CAsExC;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAaxF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBrD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA0arD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuShD"}
@@ -1 +1 @@
1
- {"version":3,"file":"convex.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/convex.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"convex.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/convex.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "struere",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "Build, test, and deploy AI agents",
5
5
  "keywords": [
6
6
  "ai",
@@ -1,3 +0,0 @@
1
- import type { ContextFunction } from '../types';
2
- export declare function defineContext(fn: ContextFunction): ContextFunction;
3
- //# sourceMappingURL=context.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/define/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAiC,MAAM,UAAU,CAAA;AAE9E,wBAAgB,aAAa,CAAC,EAAE,EAAE,eAAe,GAAG,eAAe,CAUlE"}