--- name: create-template description: Creates a new Earl HCL template for a specific API, database, or shell command. Use when adding a new service to Earl's template library, or when a pre-built template doesn't cover a needed command. --- # Create Template Creates an Earl HCL template file for a specific service and protocol. Each template defines the commands, parameters, authentication, and protocol shape for one provider. ## Process 1. **Discover** — understand what service and command to build 2. **Infer protocol** — map the user's description to one of Earl's 5 protocols 3. **Load reference** — read the protocol reference for HCL shapes and patterns 4. **Write template** — create the HCL file 5. **Review** — show the user the complete template before running it 6. **Validate** — run `earl templates validate` 7. **Secrets** — print checklist for the human to set secrets 8. **Verify** — run a test `earl call` --- ## Phase 1: Discover Intent If the request doesn't name a provider, command, and protocol, ask one question: > "What service do you want to call, and what should the command do? For example: > 'Call the GitHub API to create an issue' or 'Query my PostgreSQL database for user records'." ### Check for pre-built templates first Earl ships with 26 ready-made provider templates. If the user names a known service, check whether it is already imported before offering to import it: ```bash earl templates list ``` Check the list carefully: - If the **specific command** needed is already present (e.g. `github.create_issue` appears in the list), skip the import and go directly to Phase 7 to set any missing secrets. - If the **provider** is imported but the specific command is **not** in the list (e.g. `github` commands appear but not `github.create_issue`), skip the import and proceed to custom template authoring (phases 2–6) to add the missing command to the existing file. - If the provider is **not imported at all**, offer to import the pre-built template: ```bash # Available: github, stripe, slack, notion, openai, anthropic, recall_ai, discord, gitlab, jira, linear, # pagerduty, twilio, sendgrid, cloudflare, vercel, render, shopify, hubspot, # mailchimp, datadog, sentry, airtable, auth0, supabase, resend earl templates import https://raw.githubusercontent.com/mathematic-inc/earl/main/examples/.hcl ``` If a pre-built template was imported, skip to **Phase 7: Set Secrets** — phases 2–6 are not needed. Then continue to Phase 8 to verify the template works. Only proceed to custom template authoring (phases 2–6) if no pre-built template covers the needed command. --- ## Phase 2: Infer Protocol Map the user's description to a protocol: | User mentions | Protocol | Reference file | | -------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | REST, HTTP, API, endpoint, JSON API, webhook | `http` | `../references/http-templates.md` ([raw](https://raw.githubusercontent.com/mathematic-inc/earl/main/skills/development/references/http-templates.md)) | | GraphQL, query/mutation (in API context) | `graphql` | `../references/graphql-templates.md` ([raw](https://raw.githubusercontent.com/mathematic-inc/earl/main/skills/development/references/graphql-templates.md)) | | gRPC, protobuf, service mesh | `grpc` | `../references/grpc-templates.md` ([raw](https://raw.githubusercontent.com/mathematic-inc/earl/main/skills/development/references/grpc-templates.md)) | | shell, bash, CLI, script, command line | `bash` | `../references/bash-templates.md` ([raw](https://raw.githubusercontent.com/mathematic-inc/earl/main/skills/development/references/bash-templates.md)) | | SQL, database, postgres, mysql, sqlite | `sql` | `../references/sql-templates.md` ([raw](https://raw.githubusercontent.com/mathematic-inc/earl/main/skills/development/references/sql-templates.md)) | If the answer is genuinely ambiguous, ask one follow-up question. ### SSRF Warning If the user mentions `localhost`, `127.0.0.1`, `0.0.0.0`, or any private IP range (10.x, 172.16-31.x, 192.168.x), warn immediately: > Earl blocks requests to private and loopback IP addresses (SSRF protection). This cannot be > bypassed. Use a publicly accessible URL, or use the `bash` protocol to call local services. --- ## Phase 3: Load Reference Read the reference file for the chosen protocol before writing any HCL. The reference file contains the complete template shape, required fields, auth patterns, and known gotchas. **Critical rule for all protocols:** HCL parses before Jinja renders. All `{{ }}` expressions must be inside valid HCL string values. ```hcl # WRONG — invalid HCL: params = [{{ args.limit }}] # CORRECT — Jinja expression inside a string, rendered to a number at call time: params = ["{{ args.limit }}"] ``` --- ## Phase 4: Draft Template **Do NOT write the file to disk yet.** Compose the template content in memory — it will be written to disk only after Phase 5 human review and approval. **Target path** (determine now, write after approval): - Local (project-specific): `./templates/.hcl` - Global (all projects): `~/.config/earl/templates/.hcl` (macOS/Linux) or `%APPDATA%\earl\templates\.hcl` (Windows) Default to local if the current directory is a project (contains `.git/`, `package.json`, `Cargo.toml`, or similar). Default to global otherwise. **Provider naming:** lowercase letters and underscores only. No hyphens, dots, or uppercase. Examples: `github`, `my_company_api`, `internal_db`. **If the file already exists:** Read it first. Add the new `command` block to the existing file rather than overwriting it. **Environments (optional):** If the user needs staging/production separation, add an `environments` block at the provider level. Environment variables are available as `vars.*` in all template expressions. See the [template schema docs](https://mathematic-inc.github.io/earl/docs/template-schema#environments) for full syntax. Only add environments when the user explicitly needs them — most templates don't. **Template structure:** ```hcl version = 1 provider = "" command "" { title = "" summary = "" description = <<-EOT Parameters: - param_name: description ## Guidance for AI agents Use this command to . Example: `earl call --yes --json . --param_name value` EOT annotations { mode = "" secrets = ["."] } param "" { type = "" description = "" required = default = "" # omit if required = true } operation { protocol = "" # ... protocol-specific fields from the reference file } result { output = "{{ result }}" } } ``` **Required for every template:** - `annotations.mode`: `"read"` if the command reads data, `"write"` if it creates/modifies/deletes - `annotations.secrets`: list all secret keys the template needs (format: `"provider.key_name"`) - `description` must include a `## Guidance for AI agents` section --- ## Phase 5: Human Review (Required) Show the user the complete template content before writing the file: > "Here is the template I've drafted. Please review it before I write it to disk: > > [show full template content] > > Does this look correct? Should I write it and run `earl templates validate`?" Do not write the file or proceed until the user explicitly approves. Once written to disk, the template is immediately callable — there is no staging step. Approval here is the only gate before it becomes live. --- ## Phase 6: Validate ```bash earl templates validate ``` Fix any errors reported and re-validate. Common errors: | Error | Cause | Fix | | -------------------------------------- | ----------------------------------------- | ---------------------------------------- | | `HCL parse error` / `unexpected token` | Invalid HCL syntax | Check structure and quotes | | `template root must be an object` | Missing version/provider fields | Add `version = 1` and `provider = "..."` | | `undefined variable` in Jinja | `{{ args.x }}` doesn't match a param name | Check param names match references | | `params = [{{ ... }}]` syntax error | Bare Jinja in HCL array | Wrap in string: `["{{ ... }}"]` | --- ## Phase 7: Set Secrets Check `annotations.secrets` in the template file for required secret keys. For pre-built imports, read the imported file at `~/.config/earl/templates/.hcl` (macOS/Linux) or `%APPDATA%\earl\templates\.hcl` (Windows) to find them. Print a checklist: ```text Template ready. Set the required secrets in your terminal: earl secrets set . (Repeat for each secret listed above) Tell me when you're done and I'll verify they're set. ``` **On macOS:** Warn the user that the first `earl secrets set` run may show a system dialog asking to allow Earl keychain access — click "Always Allow" to avoid repeated prompts. After the user confirms, verify: ```bash earl secrets list ``` Check that all required keys appear. If any are missing, re-print just the missing ones. --- ## Phase 8: Verify Run a test call with representative parameters: ```bash earl call --yes --json . -- ``` **Important:** If `annotations.mode = "write"`, the test call will create/modify/delete real data. If the template defines environments (check the `environments` block for valid names), use `--env ` to select a non-production environment for the test call. Otherwise, use a test or sandbox account, a safe test value (e.g. a dedicated test repo), or choose a read-only command for the initial verification. Warn the user before running write-mode test calls. If the call fails: - HTTP 401/403 → secret not set or wrong key name - `no such command` → template not loaded, check `earl templates list` - Any other error → invoke `troubleshoot-earl` --- ## Next Steps - To add another command to this template: invoke `create-template` again for the same provider - To replace existing CLI calls with Earl: invoke `migrate-to-earl` - To enforce Earl usage at the platform level: invoke `secure-agent` - If something isn't working: invoke `troubleshoot-earl`