# Struere Documentation — CLI > Filtered section from the Struere docs. Full docs: https://docs.struere.dev/llms.txt --- ## CLI Overview > Command-line interface for managing Struere agents Source: https://docs.struere.dev/cli/overview.md The Struere CLI is your primary interface for defining, syncing, and deploying agents and platform resources. It is built with Commander.js and ships as part of the `struere` npm package. ## Available Commands | Command | Purpose | |---------|---------| | `struere init` | Initialize an organization-centric project, scaffold directories | | `struere dev` | Watch all files, sync everything to Convex on change | | `struere deploy` | Deploy all resources to production | | `struere sync` | Sync resources to Convex and exit | | `struere add ` | Scaffold a new agent, data-type, role, automation, router, eval, or fixture | | `struere data` | Browse and manage data records | | `struere status` | Compare local file definitions vs remote state | | `struere pull` | Pull remote resources to local files | | `struere logs` | View and debug agent conversations | | `struere docs` | Generate AI context files (CLAUDE.md, .cursorrules, copilot-instructions) from live docs | | `struere eval run ` | Run an eval suite and generate Markdown reports | | `struere compile-prompt ` | Compile and preview an agent's system prompt | | `struere run-tool [--agent ]` | Run a tool as it would execute during a real agent conversation | | `struere chat ` | Chat with an agent interactively or send a single message | | `struere chat --router ` | Chat via a router with routing rules evaluation | | `struere diff` | Show content differences between local and remote resources | | `struere doctor` | Run diagnostic checks on your Struere project | | `struere keys list` | List API keys for the current org and environment | | `struere keys create` | Create a new API key (plaintext shown once) | | `struere keys revoke ` | Hard-delete an API key | | `struere templates list` | List WhatsApp message templates | | `struere templates create ` | Create a new message template | | `struere templates delete ` | Delete a message template | | `struere templates status ` | Check template approval status | | `struere triggers` | Manage triggers and automation runs | | `struere triggers fire ` | Manually fire a trigger for testing | | `struere integration [provider]` | Manage integrations (airtable, resend, flow) | | `struere threads` | Manage conversation threads (list, view, archive, reset) | | `struere whatsapp` | Manage WhatsApp connections and routing | | `struere org list` | List your organizations | | `struere org create [name]` | Create a new organization | | `struere login` | Browser-based OAuth authentication | | `struere logout` | Clear stored credentials | | `struere whoami` | Display the current logged-in user and organization | ## Quick Start ```bash bun add struere bunx struere init bunx struere dev ``` ## Auto-Run Behavior The CLI automatically handles prerequisites so you never need to run setup commands manually: - **No `struere.json`?** — Automatically runs `init` before proceeding - **Not logged in?** — Automatically runs `login` before proceeding - **Stale `.struere/` shim?** — The `dev`, `sync`, `deploy`, and `status` commands auto-regenerate the `.struere/index.js`, `index.d.ts`, and `types.d.ts` virtual module files before loading resources, so you never need to manually update them when new SDK functions are added This means running `bunx struere dev` in an empty directory will walk you through project initialization and authentication before starting the development sync. ## Configuration ### Project Configuration (`struere.json`) Located at the root of your project, this file identifies your organization: ```json { "version": "2.0", "organization": { "id": "org_abc123", "slug": "acme-corp", "name": "Acme Corp" } } ``` ### Credentials (`~/.struere/credentials.json`) Authentication tokens are stored locally in your home directory. These are managed automatically by `struere login` and `struere logout`. The CLI proactively refreshes tokens 5 minutes before expiry and silently retries on auth errors, so you rarely need to re-authenticate during a session. ## Environment Variables | Variable | Default | Purpose | |----------|---------|---------| | `STRUERE_CONVEX_URL` | `your-deployment.convex.cloud` | Convex deployment URL | | `STRUERE_API_KEY` | — | API key for production deployments | | `STRUERE_AUTH_URL` | `app.struere.dev` | Auth callback URL for OAuth flow | ## Architecture The CLI is organized into command files and utility modules: ``` src/cli/ ├── index.ts # Entry point, Commander.js setup, version check ├── commands/ │ ├── init.ts # Project initialization │ ├── dev.ts # File watching and sync │ ├── deploy.ts # Production deployment │ ├── add.ts # Resource scaffolding │ ├── status.ts # Local vs remote comparison │ ├── pull.ts # Pull remote to local │ ├── eval.ts # Eval suite runner │ ├── keys.ts # API key management │ ├── templates.ts # WhatsApp template management │ ├── org.ts # Organization management │ ├── compile-prompt.ts # Compile system prompt templates │ ├── run-tool.ts # Run tools for testing │ ├── chat.ts # Interactive agent chat │ ├── logs.ts # View and debug conversations │ ├── docs.ts # Generate AI context files │ ├── triggers.ts # Manage triggers and automation runs │ ├── integration.ts # Integration config management │ ├── whatsapp.ts # WhatsApp connection management │ ├── login.ts # Browser-based OAuth │ ├── logout.ts # Clear credentials │ └── whoami.ts # Current user info └── utils/ ├── loader.ts # Load resources from directories ├── extractor.ts # Build sync payload ├── project.ts # Load/save struere.json ├── convex.ts # API calls to Convex ├── evals.ts # Eval API helpers ├── whatsapp.ts # WhatsApp template API helpers ├── scaffold.ts # File templates for new resources └── credentials.ts # Auth token management ``` ### Startup On every invocation, the CLI performs a version check against npm with a 2-second timeout. If a newer version is available, it displays an update notice. ## Sync Mechanism The CLI syncs your local definitions to the Convex backend. The sync flow is: 1. **Load** — Read all files from `agents/`, `entity-types/`, `roles/`, `triggers/`, `tools/`, `routers/`, `evals/`, and `fixtures/` directories 2. **Validate** — Check cross-resource references before syncing (router agent references, trigger entity type references, integration requirements). Errors block the sync; warnings display but allow it to continue. 3. **Extract** — Build a sync payload using `extractSyncPayload()` 4. **Sync to development** — Send agents, data types, roles, triggers, and tools to `syncOrganization` 5. **Sync to eval** — Send agents, data types, roles, tools, eval suites, and fixtures to `syncOrganization` (triggers excluded) 6. **Watch** (dev mode) — Monitor files with chokidar and re-sync on any change Resources are upserted by slug or name, meaning the CLI handles both creation and updates transparently. Fixture sync resets the eval environment on every sync (deletes all entities/relations, then recreates from YAML). ## Organization-Centric Design Struere uses an organization-centric architecture. A single project defines all resources for one organization: - All agents in `agents/` - All data types in `entity-types/` - All roles in `roles/` - All automations in `triggers/` - All routers in `routers/` - Shared custom tools in `tools/` - Eval suites in `evals/` - Fixture data in `fixtures/` This means you manage your entire platform configuration from a single codebase, with the CLI handling synchronization to the backend. --- ## struere init > Initialize an organization-centric project Source: https://docs.struere.dev/cli/init.md The `init` command scaffolds a new Struere project with all the directories and configuration needed to define agents, data types, roles, automations, and tools. ## Usage ```bash bunx struere init ``` ### Options | Flag | Description | |------|-------------| | `--org ` | Specify the organization slug directly instead of selecting interactively | | `-y, --yes` | Skip prompts and use defaults | ## What It Does 1. **Authenticates** — If you are not logged in, opens a browser for OAuth authentication 2. **Creates project structure** — Scaffolds the required directories for your resources 3. **Writes `struere.json`** — Creates the project configuration file with your organization details 4. **Generates virtual module** — Creates `.struere/index.js`, `index.d.ts`, and `types.d.ts` files. These are auto-regenerated by `dev`, `sync`, `deploy`, and `status` commands, so you never need to manually patch them when new SDK functions are added. ## Directory Structure After running `init`, your project will contain: ``` my-project/ ├── struere.json ├── agents/ ├── entity-types/ ├── roles/ ├── triggers/ ├── routers/ ├── tools/ │ └── index.ts ├── evals/ └── fixtures/ ``` | Directory | Purpose | |-----------|---------| | `agents/` | Agent definitions using `defineAgent()` | | `entity-types/` | Data type schemas using `defineData()` | | `roles/` | Role definitions with policies, scope rules, and field masks using `defineRole()` | | `triggers/` | Automations using `defineTrigger()` | | `routers/` | Router definitions using `defineRouter()` | | `tools/` | Custom tool definitions using `defineTools()` | | `evals/` | Eval suite definitions as YAML | | `fixtures/` | Fixture data for eval environment as YAML | ## struere.json The configuration file links your project to a Struere organization: ```json { "version": "2.0", "organization": { "id": "org_abc123", "slug": "acme-corp", "name": "Acme Corp" } } ``` | Field | Description | |-------|-------------| | `version` | Schema version for the configuration file | | `organization.id` | Your Clerk organization ID | | `organization.slug` | URL-friendly organization slug | | `organization.name` | Human-readable organization name | ## Organization-Centric Architecture Struere projects are organized around a single organization. All resources you define — agents, data types, roles, automations, and tools — belong to that organization. This means: - One project per organization - All agents share the same data types and roles - Custom tools defined in `tools/index.ts` are available to any agent in the organization - The CLI syncs the entire project state on every change ## Auto-Init You do not need to run `init` explicitly. If you run `struere dev` or other commands without a `struere.json` file present, the CLI will automatically run the initialization flow first. ## Next Steps After initializing, create your first resources: ```bash bunx struere add agent my-agent bunx struere add entity-type customer bunx struere add role support bunx struere dev ``` --- ## struere dev > Watch files and sync to Convex on change Source: https://docs.struere.dev/cli/dev.md The `dev` command is your primary development workflow. It loads all resource definitions from your project, syncs them to two environments — **development** and **eval** — and watches for file changes to re-sync automatically. ## Usage ```bash bunx struere dev ``` ### Options | Flag | Description | |------|-------------| | `--force` | Skip the destructive sync confirmation prompt. By default, `dev` warns you if the sync would delete remote resources not present locally. | ## How It Works The dev command follows this flow: 1. **Auto-init** — If no `struere.json` exists, runs the initialization flow 2. **Auto-login** — If not authenticated, opens a browser for OAuth 3. **Regenerate `.struere/` shim** — Auto-regenerates the virtual module files (`.struere/index.js`, `index.d.ts`, `types.d.ts`) to ensure they are up to date with the latest SDK exports 4. **Load resources** — Reads all files from `agents/`, `entity-types/`, `roles/`, `triggers/`, `tools/`, `routers/`, `evals/`, and `fixtures/` directories 5. **Validate resources** — Checks cross-resource references before syncing. Router agent references must match loaded agents, trigger entity type references must match loaded entity types, and agents using integration-dependent tools (whatsapp, calendar, airtable, email, payment) produce warnings. Errors (red ✖) block the sync; warnings (yellow ⚠) display but allow it to continue. 6. **Build sync payload** — Assembles all resources into a single payload via `extractSyncPayload()` 7. **Sync to development** — Sends agents, data types, roles, and triggers to the `syncOrganization` mutation with `environment: "development"` 8. **Sync to eval** — Sends agents, data types, roles, eval suites, and fixtures to `syncOrganization` with `environment: "eval"` (triggers excluded to prevent side effects) 9. **Watch for changes** — Uses chokidar to monitor all resource directories 10. **Re-sync on change** — When any file is added, modified, or deleted, reloads, re-validates, and re-syncs both environments ## Dual Sync The CLI makes two sync calls on every change: **Development environment** — receives agents, data types, roles, and automations: ```typescript { environment: "development", agents: [...], entityTypes: [...], roles: [...], triggers: [...] } ``` **Eval environment** — receives agents, data types, roles, eval suites, and fixtures (no automations): ```typescript { environment: "eval", agents: [...], entityTypes: [...], roles: [...], evalSuites: [...], fixtures: [...] } ``` Each resource is upserted by its slug or name, so both new resources and updates are handled transparently. Automations are excluded from the eval environment to prevent side effects during test runs. Fixture sync deletes all existing entities and relations in the eval environment and recreates them from YAML, ensuring a clean, known state on every sync. To deploy to production, use `struere deploy`. ## File Watching The CLI watches the following directories for changes: - `agents/` — Agent definition files - `entity-types/` — Data type schema files - `roles/` — Role definition files - `triggers/` — Automation definition files - `tools/` — Custom tool definition files - `routers/` — Router definition files - `evals/` — Eval suite definition files - `fixtures/` — Fixture data files When a file is added, modified, or deleted, the CLI: 1. Reloads all resources from disk 2. Builds a fresh sync payload 3. Sends the full payload to Convex This means the sync is always a complete snapshot of your local state, not incremental changes. ## Example Workflow ```bash bunx struere dev ``` With the dev command running, open a separate terminal and create resources: ```bash bunx struere add agent scheduler ``` The dev process will detect the new file and sync it automatically. Edit the generated `agents/scheduler.ts` file and save — the changes will sync within seconds. ## Convex Sync Functions The backend processes the sync payload through these functions: | Function | Purpose | |----------|---------| | `syncOrganization` | Bulk upsert all resources (agents, data types, roles, triggers, eval suites, fixtures) | | `getSyncState` | Return current remote state for comparison | The sync helpers upsert resources by slug, creating new records or updating existing ones as needed. ## Troubleshooting If the sync fails, the CLI will display the error message from Convex. Common issues include: - **Invalid schema** — Data type schemas must be valid JSON Schema objects - **Duplicate slugs** — Each resource type must have unique slugs within an organization - **Authentication expired** — The CLI automatically refreshes tokens before expiry and retries on auth errors. If automatic refresh fails, re-run `struere login` --- ## struere org > Create and manage organizations from the CLI Source: https://docs.struere.dev/cli/org.md The `org` command lets you create and list organizations directly from the CLI, without needing to visit the dashboard. ## Commands ### `struere org list` List all organizations you belong to. ```bash bunx struere org list ``` #### Options | Flag | Description | |------|-------------| | `--json` | Output as JSON | #### Example Output ``` Organizations Acme Corp (acme-corp) - admin My Side Project (my-side-project) - member ``` ### `struere org create` Create a new organization. ```bash bunx struere org create "My Organization" ``` #### Arguments | Argument | Description | |----------|-------------| | `[name]` | Organization name (prompted if not provided) | #### Options | Flag | Description | |------|-------------| | `--slug ` | Custom URL-friendly slug (auto-generated from name if not provided) | | `--json` | Output as JSON | #### What It Does 1. **Authenticates** — Verifies your CLI session 2. **Creates in Clerk** — Creates the organization via the Clerk Backend API (source of truth for auth) 3. **Syncs to Convex** — Immediately syncs the organization and your admin membership to the platform database 4. **Returns details** — Displays the new organization name, slug, and your role (always `admin` for the creator) #### Example ```bash bunx struere org create "Acme Corp" --slug acme ``` ``` ✓ Created organization Acme Corp (acme) Next steps: • struere init - Initialize a project ``` ## Integration with Init When you run `struere init` and have no organizations, the CLI will prompt you to create one inline instead of requiring a separate step. This keeps the onboarding flow seamless: ``` Not logged in - authenticating... ✓ Logged in as jane@example.com No organizations found. Create one now? (Y/n) Organization name: My Company Creating organization... ✓ Created organization My Company (my-company) Organization: My Company Creating project structure... ``` ## Non-Interactive Mode In CI/CD or non-interactive environments: - `struere org create` requires the name argument - `struere org list --json` outputs machine-readable JSON - `struere init` exits with an error and a helpful message if no organizations exist --- ## struere add > Scaffold new agents, data types, roles, and automations Source: https://docs.struere.dev/cli/add.md The `add` command scaffolds a new resource file with a starter template in the appropriate directory. ## Usage ```bash bunx struere add ``` ## Resource Types | Type | Directory | Definition Function | |------|-----------|-------------------| | `agent` | `agents/` | `defineAgent()` | | `data-type` | `entity-types/` | `defineData()` | | `role` | `roles/` | `defineRole()` | | `trigger` | `triggers/` | `defineTrigger()` | | `eval` / `suite` | `evals/` | `defineEvalSuite()` | | `router` | `routers/` | `defineRouter()` | | `fixture` | `fixtures/` | YAML fixture definition | ## Examples ### Scaffold an Agent ```bash bunx struere add agent scheduler ``` Creates `agents/scheduler.ts`: ```typescript import { defineAgent } from 'struere' export default defineAgent({ name: "Scheduler", slug: "scheduler", version: "0.1.0", description: "Scheduler Agent", model: { model: "openai/gpt-5-mini", temperature: 0.7, maxTokens: 4096, }, systemPrompt: `You are {{agentName}}, an AI assistant for {{organizationName}}. Current time: {{currentTime}} Your capabilities: - Answer questions accurately and helpfully - Use available tools when appropriate - Maintain conversation context Always be concise, accurate, and helpful.`, tools: ["entity.query", "entity.get"], }) ``` ### Scaffold a Data Type ```bash bunx struere add data-type customer ``` Creates `entity-types/customer.ts`: ```typescript import { defineData } from 'struere' export default defineData({ name: "Customer", slug: "customer", schema: { type: "object", properties: { name: { type: "string", description: "Name" }, email: { type: "string", format: "email", description: "Email address" }, status: { type: "string", enum: ["active", "inactive"], description: "Status" }, }, required: ["name"], }, searchFields: ["name", "email"], displayConfig: { listFields: ["name", "email", "status"], }, }) ``` ### Scaffold a Role ```bash bunx struere add role support ``` Creates `roles/support.ts`: ```typescript import { defineRole } from 'struere' export default defineRole({ name: "support", description: "Support role", policies: [ { resource: "*", actions: ["list", "read"], effect: "allow" }, ], scopeRules: [], fieldMasks: [], }) ``` ### Scaffold an Automation ```bash bunx struere add trigger notify-on-signup ``` Creates `triggers/notify-on-signup.ts`: ```typescript import { defineTrigger } from 'struere' export default defineTrigger({ name: "notify-on-signup", slug: "notify-on-signup", on: { entityType: "ENTITY_TYPE_HERE", action: "created", }, actions: [ { tool: "entity.query", args: { type: "{{trigger.entityType}}", filters: { "data.id": "{{trigger.entityId}}" }, }, }, ], }) ``` ### Scaffold a Router ```bash bunx struere add router support-router ``` Creates `routers/support-router.ts`: ```typescript import { defineRouter } from 'struere' export default defineRouter({ name: "Support Router", slug: "support-router", mode: "rules", agents: [ { slug: "agent-one", description: "Handles ..." }, ], rules: [ { conditions: [{ field: "channel", operator: "eq", value: "whatsapp" }], route: "agent-one", }, ], fallback: "agent-one", }) ``` ### Scaffold a Fixture ```bash bunx struere add fixture classroom-data ``` Creates `fixtures/classroom-data.fixture.yaml`: ```yaml name: "Classroom Data" slug: "classroom-data" entities: - ref: "example-1" type: "ENTITY_TYPE_HERE" data: name: "Example Entity" status: "active" - ref: "example-2" type: "ENTITY_TYPE_HERE" data: name: "Another Entity" relations: - from: "example-1" to: "example-2" type: "related_to" ``` ## With Dev Running If you have `struere dev` running in another terminal, newly scaffolded files will be detected and synced to Convex automatically. You can immediately edit the generated file and see your changes reflected in the development environment. ## Naming Conventions The `` argument is used to generate both the filename and the resource slug: - Filename: `.ts` (e.g., `scheduler.ts`, `notify-on-signup.ts`) - Slug: derived from the name (e.g., `scheduler`, `notify-on-signup`) - Display name: derived from the name with capitalization (e.g., `Scheduler`, `Notify on Signup`) --- ## struere status > Compare local vs remote state Source: https://docs.struere.dev/cli/status.md The `status` command compares your local file definitions against the current remote state in Convex, showing what would change on the next sync. ## Usage ```bash bunx struere status bunx struere status --json ``` ## Flags | Flag | Description | |------|-------------| | `--json` | Output raw JSON with classified resources | ## What It Does The `status` command: 1. Auto-regenerates the `.struere/` virtual module shim to ensure resource loading uses the latest SDK exports 2. Loads all resource definitions from your local directories (`agents/`, `entity-types/`, `roles/`, `triggers/`, `routers/`, `tools/`) 3. Fetches the current remote state for both development and production via `getSyncState` 4. Compares each resource and displays the differences ## Output Sections The status output displays five resource categories: ### Agents Shows all agents with their sync and deployment status. Agents synced to development show a green dot. Agents not yet deployed to production show a yellow dot. ### Data Types Shows all entity types with their sync status. ### Roles Shows all roles with their sync status. ### Routers Shows all routers with their sync status and mode. ### Custom Tools Shows all custom tools with their sync status. Each section categorizes resources as: - **Synced** (green dot) — Exists locally and remotely - **Not in production** (yellow dot) — Synced to dev but not deployed to production - **New** (blue +) — Exists locally but not remotely (will be created on sync) - **Will be deleted** (red -) — Exists remotely but not locally (will be removed on sync) ## Example Output ``` Agents ──────────────────────────────────────────────────────────── ● scheduler (scheduler) - v1.0.0 ○ support-agent (support-agent) - v1.2.0 Not deployed to production + onboarding-agent (onboarding-agent) - new Data Types ──────────────────────────────────────────────────────────── ● customer (customer) + invoice (invoice) - new Roles ──────────────────────────────────────────────────────────── ● admin (2 policies) - legacy-role - will be deleted Routers ──────────────────────────────────────────────────────────── ● main-router (main-router) - rules No routers Custom Tools ──────────────────────────────────────────────────────────── ● calculate-price + send-invoice - new ``` ## JSON Output Use `--json` for machine-readable output: ```bash bunx struere status --json ``` Returns a JSON object with `agents`, `entityTypes`, `roles`, and `routers`, each containing `synced`, `new`, and `deleted` arrays. ## When to Use Status - **Before deploying** — Review what will change before running `struere deploy` - **After pulling** — Verify that your local state matches remote after a `pull` - **Debugging sync issues** — Identify resources that are out of sync - **Code review** — See at a glance what a set of file changes will do to the remote state ## Workflow Integration A safe deployment workflow using `status`: ```bash bunx struere status bunx struere dev bunx struere status bunx struere deploy ``` 1. Check what will change 2. Sync to development and test 3. Verify the state is clean 4. Deploy to production ## Relationship with Other Commands | Command | What it does | |---------|-------------| | `struere status` | Read-only comparison, changes nothing | | `struere dev` | Syncs local to remote (development environment) | | `struere pull` | Syncs remote to local (overwrites local files) | | `struere deploy` | Syncs local files to production | --- ## struere pull > Pull remote resources to local files Source: https://docs.struere.dev/cli/pull.md The `pull` command downloads the current remote state from Convex and writes it to local files, creating or updating resource definitions in your project directories. ## Usage ```bash bunx struere pull bunx struere pull --force bunx struere pull --env production bunx struere pull --dry-run bunx struere pull --json ``` ## Flags | Flag | Description | |------|-------------| | `--force` | Overwrite existing local files | | `--env ` | Environment to pull from (`development` or `production`, defaults to `development`) | | `--dry-run` | Show what would be written without writing any files | | `--json` | Output results as JSON | ## What It Does The `pull` command: 1. Fetches the current state of all resources from your Convex backend for the specified environment 2. Generates local definition files for each resource 3. Writes the files to the appropriate directories ## Pulled Resources | Resource | Directory | File Pattern | |----------|-----------|-------------| | Agents | `agents/` | `agents/{slug}.ts` | | Data Types | `entity-types/` | `entity-types/{slug}.ts` | | Roles | `roles/` | `roles/{name}.ts` | | Automations | `triggers/` | `triggers/{slug}.ts` | | Routers | `routers/` | `routers/{slug}.ts` | | Custom Tools | `tools/` | `tools/index.ts` | Index files (`index.ts`) are generated for each directory that has resources. ## When to Use Pull The `pull` command is useful when: - **Resources were created via the dashboard** — If you or a team member created agents, data types, roles, or automations through the web dashboard, `pull` brings those definitions into your local project so they can be managed as code. - **Onboarding to an existing project** — When joining a team that already has resources configured in Convex, `pull` gives you the local files to start working with. - **Recovering local files** — If local files were accidentally deleted or corrupted, `pull` restores them from the remote state. - **Switching machines** — When setting up a new development environment, `pull` populates your project with the current remote definitions. - **Pulling production state** — Use `--env production` to pull production configurations locally for review or comparison. ## Example Workflow A common scenario is creating resources in the dashboard and then pulling them locally for version control: ```bash bunx struere pull git add agents/ entity-types/ roles/ triggers/ routers/ tools/ git commit -m "Pull remote resources to local definitions" ``` After pulling, you can modify the local files and use `struere dev` to sync changes back. ## Relationship with Dev and Status | Command | Direction | Purpose | |---------|-----------|---------| | `struere pull` | Remote to local | Download remote state as local files | | `struere dev` | Local to remote | Sync local files to remote | | `struere status` | Comparison | Show differences without changing anything | A typical workflow might be: 1. `struere pull` — Get the latest remote state 2. Edit local files — Make your changes 3. `struere status` — Review what will change 4. `struere dev` — Sync changes to the development environment --- ## struere deploy > Deploy all resources to production Source: https://docs.struere.dev/cli/deploy.md The `deploy` command syncs all local resource definitions directly to the **production** environment. ## Usage ```bash bunx struere deploy bunx struere deploy --dry-run bunx struere deploy --force bunx struere deploy --json bunx struere deploy --verbose ``` ## Flags | Flag | Description | |------|-------------| | `--dry-run` | Show what would be deployed without making any changes | | `--force` | Skip destructive sync confirmation prompts | | `--json` | Output results as JSON | | `-v, --verbose` | Show detailed resource information (loaded counts, per-resource sync results, timing) | ## What It Does The deploy command auto-regenerates the `.struere/` virtual module shim, loads all resource definitions from your local directories, and validates cross-resource references before syncing. Validation checks that router agent references match loaded agents, trigger entity type references match loaded entity types, and warns when agents use tools that require integration configuration (whatsapp, calendar, airtable, email, payment). Errors block the deploy; warnings display but allow it to continue. After validation, it builds a sync payload and sends it directly to the production environment via `syncOrganization`. It syncs agents, data types, roles, triggers, routers, custom tools, and fixtures. If any resources exist remotely but not locally, the command warns about deletions and asks for confirmation before proceeding (unless `--force` is used). ## Development vs Production Struere enforces full environment isolation between development and production: | Aspect | `struere dev` | `struere deploy` | |--------|---------------|------------------| | Target environment | `development` | `production` | | Data isolation | Development data, threads, events | Production data, threads, events | | API keys | Development keys only | Production keys only | | Source | Local files | Local files | When you run `struere dev`, all synced resources are created in the development environment. When you run `struere deploy`, the same local files are synced directly to production. ## Deployment Flow ``` Local files ──[struere dev]────► Development environment Local files ──[struere deploy]─► Production environment ``` Both commands read from local files. The `deploy` command does not promote from development — it syncs local definitions directly to production. ## Dry Run Use `--dry-run` to preview what would be deployed: ```bash bunx struere deploy --dry-run ``` This lists all agents, data types, roles, eval suites, and any resources that would be deleted, without making changes. ## JSON Output Use `--json` for machine-readable output: ```bash bunx struere deploy --json ``` Returns a JSON object with `success`, `environment`, and per-resource breakdowns of `created`, `updated`, and `deleted` slugs. ## Environment Scoping The following resources are scoped per environment: - Agent configurations (model, system prompt, tools) - Data types and data - Roles, policies, scope rules, and field masks - Threads and messages - Events and executions - Automation runs - API keys Agents themselves (name, slug, description) are shared across environments — only their configurations are environment-specific. ## API Key Environments API keys carry an `environment` field. When an API request arrives, the environment is extracted from the API key and threaded through the entire request: - Config lookup uses the key's environment - Threads are created in that environment - Actor context carries the environment - Tool execution respects environment boundaries - Events are logged with the environment A development API key cannot access production data, and vice versa. ## Production Checklist Before deploying, verify: 1. **Test in development** — Use `struere dev` and development API keys to test your agents thoroughly 2. **Review with `struere status`** — Compare your local definitions against the remote state 3. **Check permissions** — Ensure roles and policies are correctly configured for production use 4. **Verify API keys** — Create production API keys in the dashboard for your applications --- ## struere chat > Chat with an agent directly from the terminal Source: https://docs.struere.dev/cli/chat.md The `chat` command lets you talk to an agent directly from the terminal — either interactively or as a single message. This is for rapid iteration: test agent behavior, debug tool usage, and verify system prompts without leaving the terminal. ## Usage ```bash # Interactive chat bunx struere chat # Single message mode bunx struere chat my-agent --message "Hello" # Continue a thread bunx struere chat my-agent --thread # Different environment bunx struere chat my-agent --env production --confirm # Verbose output bunx struere chat my-agent --message "Hello" --verbose # JSON output bunx struere chat my-agent --message "Hello" --json # Custom channel bunx struere chat my-agent --channel whatsapp ``` ## Options | Flag | Description | |------|-------------| | `--env ` | Environment: `development`, `production`, or `eval`. Default: `development` | | `--message ` | Send a single message and exit. Without this flag, starts an interactive REPL | | `--thread ` | Continue an existing conversation thread | | `--channel ` | Channel identifier sent to the agent. Default: `api` | | `-v, --verbose` | Show thread ID, token breakdown, model, duration, and tool call details | | `--json` | Output structured JSON (single-message mode only) | | `--router` | Chat via a router instead of directly with an agent. The first argument becomes the router slug | | `--phone ` | Sender phone number for routing rules evaluation. Required when `--router` is used | | `--follow` | Continue in interactive mode after sending a `--message` (instead of exiting) | | `--confirm` | Skip the production environment confirmation prompt | ## Router Mode Use `--router` to chat via a router instead of directly with an agent. The router evaluates its routing rules against the message and sender phone number to select the right agent. ```bash struere chat support-router --router --phone "+56911111111" --message "Hola" ``` The CLI displays which agent was selected inline with the response: ``` Soporte Chile (soporte-chile) ← routed: Hola! En que puedo ayudarte hoy? ``` Follow-up messages with `--thread` re-run the router on every message — the chosen agent may change as routing conditions change: ```bash struere chat support-router --router --phone "+56911111111" --thread --message "Necesito ayuda" ``` The `--phone` flag is required when `--router` is used. Without it, the CLI exits with an error. ## Interactive Mode When no `--message` flag is provided, the CLI starts an interactive REPL session. The prompt shows the agent slug and environment, and the thread is maintained across messages automatically. Type `exit` or `quit` to end the session. Ctrl+C cancels an in-flight request and returns to the prompt. Ctrl+C at the prompt exits the session. ``` Chat with support (development) Type 'exit' to quit You: Hello, what can you do? Agent: I can help with bug reports, feature requests, and general questions about the platform. Tokens: 2817 You: I want to report a bug Agent: Sure! Can you describe what happened? Tokens: 1523 You: exit Goodbye! ``` ## Single-Message Mode With `--message`, the CLI sends one message and exits. This is useful for scripting, CI pipelines, and quick checks. Use `--follow` to send the initial message and then continue in interactive mode instead of exiting. ``` $ bunx struere chat support --message "What are your capabilities?" ────────────────────────────────────────────────── I can help with bug reports, feature requests, and general questions about the platform. ────────────────────────────────────────────────── ``` Combine with `--json` for structured output: ```json { "threadId": "m573ddwgnpdcrpdjes65451a0x83etn2", "message": "I can help with bug reports, feature requests, and general questions about the platform.", "usage": { "inputTokens": 2630, "outputTokens": 187, "totalTokens": 2817 } } ``` Combine with `--thread` to continue a previous conversation in a script. ## Verbose Output The `--verbose` flag adds execution metadata after the agent response: ``` Thread: m573ddwgnpdcrpdjes65451a0x83etn2 Tokens: 2630 in / 187 out (2817 total) Model: openai/gpt-5-mini Duration: 1243ms Tool Calls: ✓ entity.query — 312ms ✓ entity.create — 428ms ``` Verbose mode shows: - **Thread ID** — for continuing the conversation with `--thread` - **Token breakdown** — input, output, and total tokens - **Model** — the model ID used for the response - **Duration** — total execution time in milliseconds - **Tool calls** — each tool call with its name, status (success/failure), and duration. Failed tool calls include the error type and message. ## Authentication The command supports both authentication methods: | Method | How it works | |--------|-------------| | **API key** (`STRUERE_API_KEY`) | Calls `POST /v1/agents/{slug}/chat` on the Convex HTTP endpoint. Environment is determined by the API key. | | **Clerk session** (`struere login`) | Resolves the agent by slug, then calls the `chat:sendBySlug` action directly via the Convex API. | The CLI proactively refreshes auth tokens 5 minutes before expiry and silently retries on auth errors using `withAuthRetry()`. In interactive mode, if automatic refresh fails, the CLI prompts you to re-login without ending your session. In non-interactive mode, if neither method is available, the command exits with an error. ## Production Safety When targeting production (`--env production`), the CLI displays a confirmation prompt: ``` WARNING: Chatting against PRODUCTION environment. This will execute real operations with real data. Press Enter to continue or Ctrl+C to cancel: ``` Use `--confirm` to skip this prompt in CI/CD or scripting contexts. ## Thread Continuity - The first message creates a new thread and returns the thread ID - Subsequent messages in interactive mode automatically use the same thread - Use `--thread ` to resume a previous conversation from a new session - Thread IDs are shown in verbose mode or JSON output ## Error Cases | Scenario | Behavior | |----------|----------| | Agent slug not found | Exits with error: `Agent not found: ` | | No config for environment | Exits with error: `Agent not found or no config for environment: ` | | Not authenticated | Prompts for login or exits with error | | Request timeout (120s) | Exits with error: `Request timed out` | | Server error | Exits with error: `Server error: ` | ## Example Workflow ```bash # Edit your agent vim agents/support.ts # Sync to development bunx struere dev # Test interactively bunx struere chat support # Quick single-message test bunx struere chat support --message "Book an appointment for tomorrow" # Verbose to see token usage bunx struere chat support --message "Hello" --verbose # Test in production bunx struere chat support --env production --message "Hello" --confirm # Script: send message and pipe JSON output bunx struere chat support --message "Help" --json | jq '.message' ``` --- ## struere eval run > Run eval suites from the command line and generate Markdown result reports Source: https://docs.struere.dev/cli/eval.md The `eval run` command executes an eval suite against your agent, polls for completion, and writes results as Markdown files. ## Usage ```bash # Run all cases in a suite bunx struere eval run # Run specific case(s) by name bunx struere eval run --case "Greeting test" # Run cases matching a tag bunx struere eval run --tag "regression" ``` ### Options | Flag | Description | |------|-------------| | `--case ` | Run only cases matching the given name(s). Repeatable. | | `--tag ` | Run only cases that have at least one of the given tags. Repeatable. | | `--timeout ` | Maximum time to wait for the run to complete. Default: `300`. | ## What It Does 1. **Auto-init** and **auto-login** if needed (same as `struere dev`) 2. **Syncs** all local resources (agents, data types, roles, eval suites, fixtures) to the **eval** environment 3. **Resolves** the suite by slug — errors with a list of available slugs if not found 4. **Filters** cases by `--case` name or `--tag` if provided 5. **Starts** the eval run on the backend 6. **Polls** for completion every 3 seconds, showing a live progress spinner 7. **Prints** a results table to the terminal 8. **Writes** Markdown files to `evals/runs/` ## Terminal Output ``` Struere Eval Run Organization: My Org Suite: Basic Agent Tests (basic-agent-tests) ✓ Synced to eval environment ✓ Suite resolved (4 cases) ✓ Run completed in 45.2s Results: PASS Greeting test 4.2/5 3.1s FAIL Entity query test 1.8/5 8.4s PASS Multi-turn conversation 4.5/5 12.1s ERROR Tool restriction test - 0.0s 2 passed, 1 failed, 1 error | Score: 3.5/5 Results saved to evals/runs/2026-02-20T14-30-00_basic-agent-tests/ ``` ## Output Directory Each run creates a timestamped folder under `evals/runs/`: ``` evals/runs/ 2026-02-20T14-30-00_basic-agent-tests/ _summary.md PASS_greeting-test.md FAIL_entity-query-test.md ERROR_tool-restriction-test.md ``` - **Timestamp** uses ISO format with colons replaced by hyphens for filesystem safety - **Case filenames** are prefixed with `PASS`, `FAIL`, or `ERROR` for quick scanning - **`_summary.md`** is underscore-prefixed to sort first in directory listings ### `_summary.md` Contains a run-level overview with a results table and totals: ```markdown # Eval Run: Basic Agent Tests | Field | Value | |-------|-------| | Suite | Basic Agent Tests (`basic-agent-tests`) | | Agent | basic-agent-tests | | Timestamp | 2026-02-20T14:30:00.000Z | | Duration | 45.2s | | Status | completed | ## Results | Case | Status | Score | Duration | |------|--------|-------|----------| | Greeting test | PASS | 4.2/5 | 3.1s | | Entity query test | FAIL | 1.8/5 | 8.4s | ## Totals | Metric | Value | |--------|-------| | Passed | 2 | | Failed | 1 | | Errors | 1 | | Overall score | 3.5/5 | | Agent tokens | 12400 | | Judge tokens | 3200 | ``` ### Per-Case Files Each case file contains the full conversation with tool calls and assertion results: ```markdown # Greeting test | Field | Value | |-------|-------| | Status | PASS | | Score | 4.2/5 | | Duration | 3.1s | ## Turn 1 ### User Hello, who are you? ### Assistant Hi! I'm the support agent. How can I help you today? ### Assertions | Type | Result | Details | |------|--------|--------| | llm_judge | PASS (4/5) | Response is polite and offers help | | contains | PASS | Response contains "help" | ``` For error cases, a simple `## Error` section replaces the turn details. ## Exit Code | Exit Code | Meaning | |-----------|---------| | **0** | All cases passed | | **1** | One or more cases failed or errored | | **2** | The run timed out (exceeded `--timeout`) | This makes it suitable for CI pipelines. ## Case Filtering ### By Name Use `--case` to run specific cases. Names are matched case-insensitively: ```bash bunx struere eval run my-suite --case "Greeting test" --case "Tool usage test" ``` If no cases match, the command exits with a list of available case names. ### By Tag Use `--tag` to run cases that have at least one matching tag: ```bash bunx struere eval run my-suite --tag "regression" ``` Tags are defined per-case in the YAML: ```yaml cases: - name: "Greeting test" tags: ["regression", "basic"] turns: - user: "Hello" ``` If no cases match the tag, the command exits with a list of available tags. ## Sync Behavior Before running, the command syncs your local resources to the **eval** environment. This ensures the backend has your latest agent configuration, data types, roles, eval suites, and fixtures. The sync is identical to the eval-environment sync performed by `struere dev`. ## Example Workflow ```bash # Define an eval suite bunx struere add eval my-agent-tests # Edit evals/my-agent-tests.eval.yaml with your test cases # Run the suite bunx struere eval run my-agent-tests # Run only regression tests bunx struere eval run my-agent-tests --tag regression # Check the results cat evals/runs/*/\_summary.md ``` --- ## struere keys > Create, list, and revoke API keys from the command line Source: https://docs.struere.dev/cli/keys.md The `keys` command manages API keys for the current organization. Keys are scoped to a single environment (`development`, `production`, or `eval`) and authenticate requests to the Chat API, Data API, and CLI sync endpoints. ## Usage ```bash bunx struere keys list bunx struere keys create --name "my-app" --env development bunx struere keys revoke sk_dev_a1b2 ``` ## Subcommands ### keys list Lists all API keys for the current organization and environment. ```bash bunx struere keys list [options] ``` | Flag | Description | |------|-------------| | `--env ` | Environment: `development`, `production`, or `eval`. Default: `development` | | `--json` | Output raw JSON | **Output:** ``` ✓ Found 3 keys in development ID Name Prefix Env Created Last used ──────────── ─────────────── ────────────────── ─────────── ─────────── ─────────── k57a1b2c3d4 my-app sk_dev_a1b2**** development 2 days ago 1 hour ago k57e5f6g7h8 ci-pipeline sk_dev_e5f6**** development 5 days ago never k57i9j0k1l2 local-dev sk_dev_i9j0**** development 1 week ago 3 days ago ``` The plaintext key is never returned by `list` — only the ID, name, masked prefix, environment, creation time, and last-used timestamp are displayed. ### keys create Creates a new API key. The plaintext key is shown **once** at creation time and cannot be retrieved later — copy it into your secret store immediately. ```bash bunx struere keys create [options] ``` | Flag | Description | |------|-------------| | `--name ` | Human-readable name for the key. Prompted if omitted | | `--env ` | Environment: `development`, `production`, or `eval`. Default: `development` | | `--confirm` | Skip the production confirmation prompt | | `--json` | Output raw JSON (implies `--confirm`) | Production keys require an interactive confirmation prompt unless `--confirm` or `--json` is set. **Output:** ``` ✓ API key created ID: k57a1b2c3d4 Name: my-app Env: development Key: sk_dev_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2 Save this key now — it will not be shown again. ``` With `--json`: ```json { "id": "k57a1b2c3d4", "name": "my-app", "environment": "development", "key": "sk_dev_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2", "createdAt": 1714780800000 } ``` ### keys revoke Hard-deletes an API key. The key cannot be reactivated — issued tokens stop working immediately. ```bash bunx struere keys revoke [options] ``` | Flag | Description | |------|-------------| | `--confirm` | Skip the confirmation prompt | | `--json` | Output raw JSON (implies `--confirm`) | The identifier is resolved against the current org's keys in this order: 1. Exact match on full key ID (`k57a1b2c3d4`) 2. Suffix match on key ID (`a1b2c3d4`) 3. Exact match on full prefix (`sk_dev_a1b2`) 4. Prefix-startswith match (`sk_dev_a1b2****` → `sk_dev_a1b2`) If multiple keys match, the command exits with an error listing the candidates so you can re-run with a more specific identifier. **Output:** ``` ✓ Revoked key sk_dev_a1b2**** (my-app) ``` ## Permissions The `keys` command requires **organization admin** privileges. Non-admin members get a `403 Forbidden` response and cannot list, create, or revoke keys for the organization. ## Example: Vite SPA Frontend Create a development key for a browser-based app that calls the Struere API directly via CORS: ```bash bunx struere keys create --name "vite-frontend-dev" --env development ``` Copy the plaintext key into your local `.env`: ``` VITE_STRUERE_API_KEY=sk_dev_a1b2c3d4... ``` Use it from your Vite app via the [JavaScript client](../api/javascript-client): ```ts import { StruereClient } from 'struere/client' const struere = new StruereClient({ apiKey: import.meta.env.VITE_STRUERE_API_KEY, }) const reply = await struere.chat({ agentSlug: 'support', message: 'Hi!', }) ``` For production, mint a separate key with `--env production` and store it in your hosting provider's secret manager — never check production keys into source control or expose them in client-side bundles for high-traffic apps. ## Error Cases | Scenario | Behavior | |----------|----------| | Not an org admin | Exits with `403 Forbidden` | | Identifier matches multiple keys | Exits with a list of candidates | | Identifier matches no keys | Exits with `Key not found: ` | | Production env without `--confirm` or `--json` | Prompts for confirmation | --- ## struere templates > Manage WhatsApp message templates from the command line Source: https://docs.struere.dev/cli/templates.md The `templates` command manages WhatsApp message templates directly from the CLI. Templates are required for outbound messages outside the 24-hour messaging window and must be approved by Meta before use. ## Usage ```bash # List all templates bunx struere templates list # Create a template from a JSON file bunx struere templates create order_update --file template.json # Create a template with inline JSON bunx struere templates create order_update --components '[{"type":"BODY","text":"Hello {{1}}","example":{"body_text":[["World"]]}}]' # Check template approval status bunx struere templates status order_update # Delete a template bunx struere templates delete order_update ``` ## Subcommands ### templates list Lists all message templates for a WhatsApp connection. ```bash bunx struere templates list [options] ``` | Flag | Description | |------|-------------| | `--env ` | Environment (`development` or `production`). Default: `production` | | `--connection ` | WhatsApp connection ID. Auto-resolved if only one connection exists | | `--json` | Output raw JSON | **Output:** ``` ✓ Found 3 templates Name Category Language Status ───────────────────────────── ──────────────── ────────── ──────────── order_update UTILITY en_US APPROVED welcome_message MARKETING en_US PENDING verify_otp AUTHENTICATION en_US APPROVED ``` ### templates create Creates a new message template on Meta via the Kapso proxy. ```bash bunx struere templates create [options] ``` | Flag | Description | |------|-------------| | `--env ` | Environment. Default: `production` | | `--connection ` | WhatsApp connection ID | | `--language ` | Language code. Default: `en_US` | | `--category ` | Category: `UTILITY`, `MARKETING`, or `AUTHENTICATION`. Default: `UTILITY` | | `--components ` | Components as a JSON string | | `--file ` | Read components from a JSON file | | `--allow-category-change` | Allow Meta to reassign the category | | `--json` | Output raw JSON | Either `--components` or `--file` is required. The file can contain a JSON array of components or an object with a `components` key. **Example component file (`template.json`):** ```json [ { "type": "BODY", "text": "Hi {{customer_name}}, your order {{order_id}} is ready for pickup.", "example": { "body_text_named_params": [ { "param_name": "customer_name", "example": "Alex" }, { "param_name": "order_id", "example": "ORDER-123" } ] } }, { "type": "FOOTER", "text": "Reply STOP to opt out" } ] ``` **Output:** ``` ✓ Template "order_update" created ID: 1234567890 Status: PENDING Category: UTILITY ``` ### templates edit Edits an existing message template on Meta. You can update the components, category, or language. ```bash bunx struere templates edit [options] ``` | Flag | Description | |------|-------------| | `--env ` | Environment. Default: `production` | | `--connection ` | WhatsApp connection ID | | `--components ` | Updated components as a JSON string | | `--file ` | Read updated components from a JSON file | | `--category ` | New category: `UTILITY`, `MARKETING`, or `AUTHENTICATION` | | `--language ` | Language code. Default: `en_US` | Either `--components` or `--file` is required. ### templates delete Deletes a message template from Meta. This action is irreversible. ```bash bunx struere templates delete [options] ``` | Flag | Description | |------|-------------| | `--env ` | Environment. Default: `production` | | `--connection ` | WhatsApp connection ID | | `--yes` | Skip confirmation prompt | ### templates status Checks the current approval status and details of a template. ```bash bunx struere templates status [options] ``` | Flag | Description | |------|-------------| | `--env ` | Environment. Default: `production` | | `--connection ` | WhatsApp connection ID | | `--json` | Output raw JSON | **Output:** ``` ✓ Template "order_update" found Name: order_update Status: APPROVED Category: UTILITY Language: en_US Components: [ { "type": "BODY", "text": "Hi {{customer_name}}, your order {{order_id}} is ready." } ] ``` ## Connection Resolution All subcommands need a WhatsApp connection ID. The CLI resolves this automatically: - **One connected number** — used automatically - **Multiple connected numbers** — prompts you to specify `--connection ` - **No connected numbers** — exits with an error ## Template Categories | Category | Use Case | |----------|----------| | `UTILITY` | Transactional updates (order confirmations, appointment reminders) | | `MARKETING` | Promotional content and offers | | `AUTHENTICATION` | OTP/verification codes (special Meta rules apply) | ## Template Status Flow Templates go through Meta's review process: ``` Created → PENDING → APPROVED → REJECTED → PAUSED ``` Use `struere templates status ` to check the current state. ## Component Rules - **HEADER** (optional): TEXT, IMAGE, VIDEO, or DOCUMENT format - **BODY** (required): main message text with variables - **FOOTER** (optional): short text, no variables allowed - **BUTTONS** (optional): QUICK_REPLY, URL, or PHONE_NUMBER ### Parameter Formats - **NAMED** (recommended): `{{customer_name}}` — use `parameter_format: "NAMED"` at creation - **POSITIONAL**: `{{1}}`, `{{2}}` — sequential, no gaps If variables appear in HEADER or BODY, you must include examples in the component definition. ### Button Ordering Do not interleave QUICK_REPLY buttons with URL/PHONE_NUMBER buttons. Valid: `QUICK_REPLY, QUICK_REPLY, URL, PHONE_NUMBER` Invalid: `QUICK_REPLY, URL, QUICK_REPLY` ## Example Workflow ```bash # Create a template from a file bunx struere templates create order_ready \ --category UTILITY \ --language en_US \ --file templates/order_ready.json # Check if it's been approved bunx struere templates status order_ready # List all templates bunx struere templates list # Clean up a rejected template bunx struere templates delete order_ready --yes ``` --- ## struere integration > Configure and manage integrations from the command line Source: https://docs.struere.dev/cli/integration.md The `integration` command configures third-party integrations directly from the CLI. Currently supports **Airtable**, **Resend**, and **Flow** providers. These are the same integrations available in the dashboard Settings page, but configurable without leaving the terminal. ## Usage ```bash # List all configured integrations bunx struere integration # Show current config for a provider bunx struere integration airtable # Save Airtable config bunx struere integration airtable --token pat123abc # Save and verify connection bunx struere integration airtable --token pat123abc --test # Remove an integration bunx struere integration airtable --remove # Save Resend config bunx struere integration resend --from-email noreply@example.com --from-name "My App" ``` ## Listing Integrations Running `struere integration` with no arguments lists all configured integrations for the current environment. ```bash bunx struere integration [options] ``` | Flag | Description | |------|-------------| | `--env ` | Environment (`development` or `production`). Default: `development` | | `--json` | Output raw JSON | **Output:** ``` ✓ Found 2 integrations Provider Status Last Verified ──────────────── ──────────── ────────────────────── airtable active 2/26/2026, 10:30:00 AM resend inactive never ``` ## Viewing a Provider Pass a provider name with no config flags to see the current configuration. Sensitive values (tokens, keys) are masked automatically by the server. ```bash bunx struere integration [options] ``` | Flag | Description | |------|-------------| | `--env ` | Environment. Default: `development` | | `--json` | Output raw JSON | **Output:** ``` ✓ airtable config loaded airtable ──────────────────────────────────────────────────── Status: active Environment: development Last Verified: 2/26/2026, 10:30:00 AM Updated: 2/26/2026, 10:28:00 AM Config ──────────────────────────────────────────────────── personalAccessToken pat1...xyz9 defaultBaseId appABC123 ``` ## Configuring Airtable ```bash bunx struere integration airtable [options] ``` | Flag | Description | |------|-------------| | `--token ` | Airtable Personal Access Token | | `--base-id ` | Default Airtable base ID | | `--test` | Test connection after saving | | `--env ` | Environment. Default: `development` | The `--token` flag is required for initial setup. The `--base-id` is optional and sets a default base for queries. Both flags can be used independently to update individual values — the server merges updates into the existing config. **Example:** ```bash # Initial setup with verification bunx struere integration airtable --token patXXX.YYYY --base-id appZZZ --test # Update just the base ID later bunx struere integration airtable --base-id appNEW ``` ## Configuring Resend ```bash bunx struere integration resend [options] ``` | Flag | Description | |------|-------------| | `--from-email ` | Default sender email address | | `--from-name ` | Default sender display name | | `--reply-to ` | Default reply-to address | | `--test` | Test connection after saving | | `--env ` | Environment. Default: `development` | All flags are optional individually, but at least one is required when saving. The Resend API key itself is configured as a Convex environment variable (`RESEND_API_KEY`), not through this command. **Example:** ```bash bunx struere integration resend \ --from-email noreply@example.com \ --from-name "My App" \ --reply-to support@example.com \ --test ``` ## Testing a Connection Use `--test` to verify that the integration is working. This calls the backend's `testConnection` action, which validates credentials against the provider's API. ```bash # Test after saving config bunx struere integration airtable --token patXXX --test # Test existing config without changing anything bunx struere integration airtable --test ``` **Output (success):** ``` ✓ airtable config saved ✓ Airtable connection verified ``` **Output (failure):** ``` ✓ airtable config saved ✗ Airtable Personal Access Token is invalid or unreachable ``` ## Enabling and Disabling Toggle an integration between `active` and `inactive` without removing its configuration. ```bash bunx struere integration airtable --disable bunx struere integration airtable --enable ``` ## Removing an Integration Permanently deletes the integration configuration. Prompts for confirmation unless `--yes` is passed. ```bash bunx struere integration airtable --remove bunx struere integration airtable --remove --yes ``` ## Supported Providers | Provider | Required Flags | Optional Flags | |----------|----------------|----------------| | `airtable` | `--token` | `--base-id` | | `resend` | At least one of `--from-email`, `--from-name`, `--reply-to` | — | | `flow` | `--api-url`, `--api-key`, `--secret-key` | `--return-url` | ## Example Workflow ```bash # Set up Airtable with verification bunx struere integration airtable --token patXXX.YYYY --test # Set up Flow.cl payments bunx struere integration flow \ --api-url https://www.flow.cl/api \ --api-key YOUR_API_KEY \ --secret-key YOUR_SECRET_KEY \ --return-url https://yoursite.com/payment/complete \ --test # Confirm it shows up in the list bunx struere integration # Later, disable it temporarily bunx struere integration airtable --disable # Re-enable and verify bunx struere integration airtable --enable bunx struere integration airtable --test # Remove when no longer needed bunx struere integration airtable --remove --yes ``` --- ## struere compile-prompt > Compile and preview an agent's system prompt after template processing Source: https://docs.struere.dev/cli/compile-prompt.md The `compile-prompt` command compiles an agent's system prompt by resolving all template variables and embedded queries, then prints the result. This is useful for debugging template syntax, verifying that `{{entity.query(...)}}` calls return the expected data, and confirming how `{{threadContext.params.X}}` values affect the prompt. ## Usage ```bash # Compile the default prompt bunx struere compile-prompt # Compile with sample context bunx struere compile-prompt my-agent --message "Hello" --channel whatsapp # Pass thread params bunx struere compile-prompt my-agent --param studentId=abc123 --param lang=en # Compile against production bunx struere compile-prompt my-agent --env production # Output full JSON (raw + compiled + context) bunx struere compile-prompt my-agent --json # Show raw uncompiled template bunx struere compile-prompt my-agent --raw ``` ## Options | Flag | Description | |------|-------------| | `--env ` | Environment: `development` or `production`. Default: `development` | | `--message ` | Sample message injected as `{{message}}` in the template context | | `--channel ` | Sample channel (`whatsapp`, `widget`, `api`, `dashboard`) injected as `{{threadContext.channel}}` | | `--param ` | Custom thread parameter. Repeatable. Injected as `{{threadContext.params.}}`. Values support JSON parsing (numbers and booleans are auto-detected) | | `--json` | Output full JSON with `raw`, `compiled`, and `context` fields | | `--phone ` | Shorthand for `--param phoneNumber=` | | `--raw` | Show the raw uncompiled template instead of the compiled output | ## What It Does 1. Resolves the agent by slug in the target environment 2. Loads the agent's system prompt template and tool list 3. Builds a sample template context with the provided options (message, channel, params) or defaults 4. Executes all embedded queries (`{{entity.query(...)}}`, `{{event.query(...)}}`, etc.) with the agent's permissions 5. Resolves all template variables (`{{agentName}}`, `{{currentTime}}`, `{{entityTypes}}`, etc.) 6. Prints the compiled result ## Default Output ``` ✓ Compiled prompt Compiled System Prompt ──────────────────────────────────────────────────────── You are Support Agent, an assistant for My Organization. Current time: 2026-02-28T14:30:00.000Z Available data types: [{"name":"Teacher","slug":"teacher",...},{"name":"Student","slug":"student",...}] Use entity.query to search for records by type. ──────────────────────────────────────────────────────── ``` ## JSON Output With `--json`, the command outputs a JSON object containing the raw template, compiled result, and full template context: ```json { "success": true, "raw": "You are {{agentName}}, an assistant for {{organizationName}}.\nCurrent time: {{currentTime}}\n...", "compiled": "You are Support Agent, an assistant for My Organization.\nCurrent time: 2026-02-28T14:30:00.000Z\n...", "context": { "organizationId": "org_abc123", "organizationName": "My Organization", "agentName": "Support Agent", "agent": { "name": "Support Agent", "slug": "support" }, "message": "Hello", "threadContext": { "channel": "whatsapp", "params": { "studentId": "abc123" } }, "entityTypes": [...], "roles": [...] } } ``` ## Authentication The command supports both authentication methods: | Method | How it works | |--------|-------------| | **API key** (`STRUERE_API_KEY`) | Calls `POST /v1/compile-prompt` on the Convex HTTP endpoint. Environment is determined by the API key. | | **Clerk session** (`struere login`) | Resolves the agent by slug, then calls the `compileSystemPrompt` action directly via the Convex API. | If neither is available, the command prompts you to log in (interactive mode) or exits with an error (non-interactive mode). ## Template Debugging Use `compile-prompt` to verify template behavior in common scenarios: ### Verify variable resolution ```bash bunx struere compile-prompt my-agent --raw bunx struere compile-prompt my-agent ``` Compare the raw template against the compiled output to confirm all variables resolve correctly. ### Test channel-specific prompts ```bash bunx struere compile-prompt my-agent --channel whatsapp bunx struere compile-prompt my-agent --channel widget ``` If your system prompt branches on `{{threadContext.channel}}`, use this to verify each channel produces the expected prompt. ### Test parameterized prompts ```bash bunx struere compile-prompt my-agent --param customerId=ent_abc123 ``` If your prompt uses `{{entity.get({"type": "customer", "id": "{{threadContext.params.customerId}}"})}}`, this confirms the nested template resolves and the entity data loads correctly. ### Inspect embedded query results ```bash bunx struere compile-prompt my-agent --json | jq '.compiled' ``` The compiled output shows the actual data returned by `{{entity.query(...)}}` calls, which helps verify that scope rules and field masks are applied correctly. ## Error Cases | Scenario | Behavior | |----------|----------| | Agent slug not found | Exits with error: `Agent not found: ` | | No config for environment | Exits with error: `Agent not found or no config for environment: ` | | Not authenticated | Prompts for login or exits with error | | Template function fails | Embedded query errors appear as `[TEMPLATE_ERROR: ...]` in the compiled output | ## Example Workflow ```bash # Edit your agent's system prompt vim agents/support.agent.ts # Sync to development bunx struere dev # Compile and preview the prompt bunx struere compile-prompt support # Test with WhatsApp context bunx struere compile-prompt support --channel whatsapp --param customerId=ent_123 # Check the raw template bunx struere compile-prompt support --raw # Verify production prompt bunx struere compile-prompt support --env production ``` --- ## struere run-tool > Run a tool as it would execute during a real agent conversation Source: https://docs.struere.dev/cli/run-tool.md The `run-tool` command executes a tool exactly as it would during a real agent conversation — with the same permission checks, identity resolution, and sandbox infrastructure. This is especially useful for testing custom tools that run on the isolated tool-executor service, where debugging is harder. ## Usage ```bash # Run a built-in tool with agent context bunx struere run-tool --agent --args '' # Query entities as an agent bunx struere run-tool entity.query --agent support --args '{"type": "contact", "limit": 5}' # Create an entity as an agent bunx struere run-tool entity.create --agent support --args '{"type": "order", "data": {"amount": 100}}' # Run against production bunx struere run-tool entity.query --agent support --env production --args '{"type": "contact"}' --confirm # Read args from a file bunx struere run-tool my-custom-tool --agent support --args-file ./test-args.json # Output full JSON result bunx struere run-tool entity.query --agent support --args '{"type": "contact"}' --json ``` ## Agentless Mode Run tools without an agent by omitting the `--agent` flag. The tool executes as the **system actor** with full permissions and no agent-specific identity resolution. This is useful for testing tools used by triggers or validating tool behavior independently of any agent configuration. ```bash # Run a tool without agent context bunx struere run-tool entity.query --args '{"type": "contact", "limit": 5}' # Test a tool used in a trigger bunx struere run-tool entity.create --args '{"type": "notification", "data": {"message": "test"}}' # Agentless mode against production bunx struere run-tool entity.query --env production --args '{"type": "contact"}' --confirm ``` ## Options | Flag | Description | |------|-------------| | `--agent ` | Agent slug to run the tool as. If omitted, runs in agentless mode (system actor) | | `--env ` | Environment: `development` or `production`. Default: `development` | | `--args ` | Tool arguments as a JSON string. Default: `{}` | | `--args-file ` | Read tool arguments from a JSON file instead of `--args` | | `--json` | Output the full JSON result including tool metadata, duration, and identity | | `--confirm` | Skip the production confirmation prompt | ## What It Does **With `--agent`:** 1. Resolves the agent by slug in the target environment 2. Finds the tool in the agent's tool configuration 3. Builds an ActorContext with the agent's permissions and identity mode 4. Checks tool permissions via the permission engine 5. Routes execution: built-in tools run in Convex, custom tools run on the isolated tool executor 6. Returns the result with execution metadata **Agentless (no `--agent`):** 1. Builds a system ActorContext with full permissions 2. Routes execution directly (no agent-level permission checks) 3. Returns the result with execution metadata ## Default Output ``` ✔ Ran entity.query on support (development) in 245ms ────────────────────────────────────────────────── [{ "_id": "abc123", "data": { "name": "John Doe" } }] ────────────────────────────────────────────────── Identity: user (inherit mode) ``` ## JSON Output With `--json`, the command outputs the full result object: ```json { "tool": { "name": "entity.query", "isBuiltin": true }, "agent": { "name": "Support Bot", "slug": "support" }, "environment": "development", "result": [{ "_id": "abc123", "data": { "name": "John Doe" } }], "durationMs": 245, "identity": { "actorType": "user", "identityMode": "inherit" } } ``` ## Authentication The command supports both authentication methods: | Method | How it works | |--------|-------------| | **API key** (`STRUERE_API_KEY`) | Calls `POST /v1/run-tool` on the Convex HTTP endpoint. Environment is determined by the API key. | | **Clerk session** (`struere login`) | Resolves the agent by slug, then calls the `runTool` action directly via the Convex API. | If neither is available, the command prompts you to log in (interactive mode) or exits with an error (non-interactive mode). ## Production Safety When targeting production (`--env production`), the CLI displays a confirmation prompt: ``` WARNING: Running tool against PRODUCTION environment. This will execute real operations with real data. Press Enter to continue or Ctrl+C to cancel: ``` Use `--confirm` to skip this prompt in CI/CD or scripting contexts. ## Custom Tools Custom tools are the primary use case for `run-tool`. These tools run on the isolated tool executor service (Fly.io) in an isolated environment, making them harder to debug through normal conversation testing. ```bash # Test a custom tool bunx struere run-tool check-inventory --agent my-agent --args '{"productId": "SKU-123"}' # Test with complex args from a file echo '{"query": "SELECT * FROM orders", "limit": 10}' > test-args.json bunx struere run-tool run-query --agent my-agent --args-file test-args.json ``` Custom tool execution follows the exact same path as production: - Handler code is sent to the tool-executor service - The Struere SDK proxy is available (`struere.entity`, `struere.whatsapp`, etc.) - Fetch is unrestricted — custom tools have access to the native fetch function with no domain restrictions - Callbacks to built-in tools go through the permission engine ## Error Cases | Scenario | Behavior | |----------|----------| | Agent slug not found | `not_found: Agent not found or no config for this environment` | | Tool not on agent | `tool_not_found: Tool not found on this agent` | | Permission denied | `permission_denied: ` | | Custom tool has no handler | `no_handler: Custom tool has no handler code` | | Tool execution fails | `execution_error: ` | | Invalid JSON args | `Invalid JSON: ` | | Not authenticated | Prompts for login or exits with error | ## Example Workflow ```bash # Define a custom tool in tools/index.ts vim tools/index.ts # Sync to development bunx struere dev # Test the tool directly bunx struere run-tool my-custom-tool --agent my-agent --args '{"input": "test"}' # Test with different arguments bunx struere run-tool my-custom-tool --agent my-agent --args-file fixtures/tool-test.json # Verify it works in production bunx struere run-tool my-custom-tool --agent my-agent --env production --args '{"input": "test"}' --confirm # Get full JSON for debugging bunx struere run-tool my-custom-tool --agent my-agent --args '{"input": "test"}' --json ``` ## Dashboard The same tool testing functionality is available in the Struere dashboard: - **Agent Tools tab** — Click the play button next to any tool to test it inline with a JSON editor - **Tool Playground** (`/system/tools/playground`) — Standalone page where you can select any agent and tool, edit arguments, and run with full result display Both use the same execution path as the CLI command. --- ## struere threads > Manage conversation threads Source: https://docs.struere.dev/cli/threads.md The `threads` command lets you list, view, archive, and reset conversation threads from the terminal. ## Usage ```bash bunx struere threads list bunx struere threads view bunx struere threads archive bunx struere threads reset --phone "+56912345678" ``` ## Subcommands ### threads list List conversation threads. ```bash bunx struere threads list bunx struere threads list --channel whatsapp --env production bunx struere threads list --limit 10 --json ``` | Flag | Description | |------|-------------| | `--env ` | Environment: `development`, `production`, or `eval`. Default: `development` | | `--channel ` | Filter by channel: `whatsapp`, `api`, `widget`, `dashboard` | | `--limit ` | Number of threads to return. Default: `25` | | `--json` | Output results as JSON | The output table shows: | Column | Description | |--------|-------------| | ID | Thread ID | | Channel | Channel type (whatsapp, api, widget, dashboard) | | Participant | Contact name or phone number | | Agent | Currently assigned agent slug | | Last Message | Truncated last message text | | Time | Relative timestamp of last activity | ### threads view View thread details and recent messages. ```bash bunx struere threads view m57abc123 bunx struere threads view m57abc123 --env production --json ``` | Flag | Description | |------|-------------| | `--env ` | Environment: `development`, `production`, or `eval`. Default: `development` | | `--json` | Output results as JSON | Displays the thread metadata (channel, agent, participant, creation time) followed by the most recent messages with role labels and timestamps. ### threads archive Archive a thread, freeing its `externalId` for reuse. ```bash bunx struere threads archive m57abc123 bunx struere threads archive m57abc123 --env production --confirm ``` | Flag | Description | |------|-------------| | `--env ` | Environment: `development`, `production`, or `eval`. Default: `development` | | `--confirm` | Skip production environment confirmation prompt | | `--json` | Output results as JSON | Archiving a thread marks it as inactive. For WhatsApp threads, this frees the `externalId` so that the next inbound message from that phone number creates a fresh thread. ### threads reset Archive a thread by phone number. Finds the active thread for the given phone number and archives it. ```bash bunx struere threads reset --phone "+56912345678" bunx struere threads reset --phone "+56912345678" --env production --confirm ``` | Flag | Description | |------|-------------| | `--phone ` | Phone number to look up (required) | | `--env ` | Environment. Default: `production` | | `--confirm` | Skip production environment confirmation prompt | | `--json` | Output results as JSON | This is a shortcut for finding a WhatsApp thread by phone number and archiving it in one step. ## Examples ```bash # List WhatsApp threads in production bunx struere threads list --channel whatsapp --env production # View a specific thread bunx struere threads view m57abc123 # Archive a thread in production bunx struere threads archive m57abc123 --env production --confirm # Reset a WhatsApp thread by phone number bunx struere threads reset --phone "+56912345678" --env production ``` ## Error Cases | Scenario | Behavior | |----------|----------| | Thread ID not found | Exits with error: `Thread not found: ` | | Phone number has no active thread | Exits with error: `No active thread found for ` | | Not authenticated | Prompts for login or exits with error | --- ## struere doctor > Run diagnostic checks on your Struere project Source: https://docs.struere.dev/cli/doctor.md The `doctor` command runs a suite of diagnostic checks against your project and environment, surfacing configuration issues, stuck threads, unhealthy triggers, and sync drift. ## Usage ```bash bunx struere doctor bunx struere doctor --env production bunx struere doctor --json ``` ## Flags | Flag | Description | |------|-------------| | `--env ` | Environment: `development`, `production`, or `eval`. Default: `development` | | `--json` | Output results as JSON | ## Checks The doctor runs 7 diagnostic checks: | Check | What it does | |-------|-------------| | WhatsApp connection | Checks if any agents use WhatsApp tools and verifies a connection exists | | Template approvals | Checks if any agents use template tools and verifies templates are approved | | Entity type references | Validates that all trigger entity type references exist locally | | Model config | Validates agent model configurations: temperature (0-2) and maxTokens (>0) | | Stuck threads | Detects threads with >500 messages or empty agent responses | | Trigger health | Computes per-trigger failure rates. Warns above 20%, errors above 50% | | Sync drift | Compares local resource definitions against remote state | ## Output Each check displays a colored status icon: | Icon | Meaning | |------|---------| | `●` (green) | Passed | | `●` (yellow) | Warning | | `✖` (red) | Error | The command exits with code `1` if any checks report an error. ## Example Output ``` Struere Doctor (development) ● WhatsApp connection No WhatsApp tools used ● Template approvals No template tools used ● Entity type references All triggers reference valid types ● Model config All agent model configs valid ● Stuck threads No stuck threads detected ✖ Trigger health "my-trigger" 57% failure rate ● Sync drift Local and remote are in sync Summary: 6 passed, 1 error ``` ## JSON Output Use `--json` for machine-readable output: ```bash bunx struere doctor --json ``` Returns a JSON object with an array of check results, each containing `name`, `status` (`pass`, `warn`, or `error`), and `message`. ```json { "environment": "development", "checks": [ { "name": "WhatsApp connection", "status": "pass", "message": "No WhatsApp tools used" }, { "name": "Template approvals", "status": "pass", "message": "No template tools used" }, { "name": "Entity type references", "status": "pass", "message": "All triggers reference valid types" }, { "name": "Model config", "status": "pass", "message": "All agent model configs valid" }, { "name": "Stuck threads", "status": "pass", "message": "No stuck threads detected" }, { "name": "Trigger health", "status": "error", "message": "\"my-trigger\" 57% failure rate" }, { "name": "Sync drift", "status": "pass", "message": "Local and remote are in sync" } ], "summary": { "passed": 6, "warnings": 0, "errors": 1 } } ``` ## When to Use Doctor - **Before deploying** -- Catch configuration issues before they hit production - **After setting up integrations** -- Verify WhatsApp connections and template approvals - **Debugging trigger failures** -- Identify triggers with high failure rates - **Routine health checks** -- Run periodically to detect sync drift or stuck threads --- ## struere diff > Show content differences between local and remote resources Source: https://docs.struere.dev/cli/diff.md The `diff` command compares your local resource definitions against the remote deployed state, showing per-field content diffs with colored `+`/`-` lines. ## Usage ```bash bunx struere diff bunx struere diff --env production bunx struere diff --resource agents --name support bunx struere diff --stat ``` ## Flags | Flag | Description | |------|-------------| | `--env ` | Environment: `development`, `production`, or `eval`. Default: `development` | | `--resource ` | Filter by resource type: `agents`, `triggers`, `entity-types`, `roles`, `routers` | | `--name ` | Filter to a specific resource by slug | | `--json` | Output results as structured JSON | | `--stat` | Show summary only (changed field counts), no content diff | ## What It Does The `diff` command: 1. Loads all local resource definitions from your project directories 2. Fetches the current remote state for the target environment 3. Compares each resource field-by-field 4. Displays a unified diff with colored `+`/`-` lines for each changed field Resources that exist only locally are shown as entirely new (`+`). Resources that exist only remotely are shown as deletions (`-`). ## Example Output ``` agents/support (support) ──────────────────────────────────────────────────────────── systemPrompt: - You are a helpful support agent. + You are a helpful support agent for Acme Corp. model: - openai/gpt-5-mini + anthropic/claude-sonnet-4 triggers/daily-report (daily-report) ──────────────────────────────────────────────────────────── schedule: - 0 9 * * * + 0 8 * * * ``` ## Stat Mode Use `--stat` for a summary without the full diff content: ```bash bunx struere diff --stat ``` ``` agents/support 2 fields changed triggers/daily-report 1 field changed 2 resources changed, 3 fields total ``` ## JSON Output Use `--json` for machine-readable output: ```bash bunx struere diff --json ``` Returns a JSON object with per-resource diffs, each containing the resource type, slug, and an array of field changes with `field`, `local`, and `remote` values. ## Filtering Narrow the diff to a specific resource type or individual resource: ```bash # Only show agent diffs bunx struere diff --resource agents # Only show diffs for a specific agent bunx struere diff --resource agents --name support # Only show trigger diffs in production bunx struere diff --resource triggers --env production ``` ## Relationship with Other Commands | Command | What it does | |---------|-------------| | `struere status` | Shows which resources are new, synced, or deleted (no content diff) | | `struere diff` | Shows per-field content differences between local and remote | | `struere deploy` | Syncs local files to production | | `struere pull` | Syncs remote to local (overwrites local files) | Use `struere status` to see which resources changed at a glance, then `struere diff` to inspect exactly what changed before deploying.