{"id":44092497,"url":"https://github.com/sekia-ai/sekia","last_synced_at":"2026-03-01T09:04:37.040Z","repository":{"id":336809052,"uuid":"1151182073","full_name":"sekia-ai/sekia","owner":"sekia-ai","description":"A multi-agent event bus for automating workflows.","archived":false,"fork":false,"pushed_at":"2026-02-11T21:16:04.000Z","size":42174,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-12T06:25:22.090Z","etag":null,"topics":["ai","ai-agents","go","golang","lua"],"latest_commit_sha":null,"homepage":"https://sekia.ai","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sekia-ai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-06T06:32:07.000Z","updated_at":"2026-02-11T21:15:08.000Z","dependencies_parsed_at":"2026-02-12T00:05:49.413Z","dependency_job_id":null,"html_url":"https://github.com/sekia-ai/sekia","commit_stats":null,"previous_names":["sekia-ai/sekia"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/sekia-ai/sekia","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sekia-ai%2Fsekia","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sekia-ai%2Fsekia/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sekia-ai%2Fsekia/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sekia-ai%2Fsekia/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sekia-ai","download_url":"https://codeload.github.com/sekia-ai/sekia/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sekia-ai%2Fsekia/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29438641,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T05:24:35.651Z","status":"ssl_error","status_checked_at":"2026-02-14T05:24:34.830Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","ai-agents","go","golang","lua"],"created_at":"2026-02-08T11:15:27.205Z","updated_at":"2026-03-01T09:04:37.019Z","avatar_url":"https://github.com/sekia-ai.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg width=128 src=\"logo.png\" /\u003e\n\n[![CI](https://github.com/sekia-ai/sekia/actions/workflows/ci.yml/badge.svg)](https://github.com/sekia-ai/sekia/actions/workflows/ci.yml) [![Dependabot Updates](https://github.com/sekia-ai/sekia/actions/workflows/dependabot/dependabot-updates/badge.svg)](https://github.com/sekia-ai/sekia/actions/workflows/dependabot/dependabot-updates) [![pages-build-deployment](https://github.com/sekia-ai/sekia/actions/workflows/pages/pages-build-deployment/badge.svg)](https://github.com/sekia-ai/sekia/actions/workflows/pages/pages-build-deployment) [![Release](https://github.com/sekia-ai/sekia/actions/workflows/release.yml/badge.svg)](https://github.com/sekia-ai/sekia/actions/workflows/release.yml)\n\n# sekia\n\nA multi-agent event bus for automating workflows across GitHub, Gmail, Google Calendar, Linear, and Slack. Built on embedded NATS with JetStream.\n\n**[Documentation](https://sekia.ai/docs/)** \u0026middot; **[Website](https://sekia.ai)**\n\nSeven binaries — `sekiad` (daemon), `sekiactl` (CLI), four agents (`sekia-github`, `sekia-slack`, `sekia-linear`, `sekia-google`), and `sekia-mcp` (MCP server) — communicate over NATS. The daemon and CLI also use a Unix socket.\n\n## Architecture\n\n```\n┌──────────────────────────────────────────────────────────────┐\n│                            sekiad                            │\n│                                                              │\n│  ┌───────────────┐  ┌──────────┐  ┌───────────┐  ┌────────┐  │\n│  │ Embedded NATS │  │ Registry │  │ Workflow  │  │  HTTP  │  │\n│  │ + JetStream   │  │          │  │  Engine   │  │  API   │  │\n│  └───────────────┘  └──────────┘  └───────────┘  └────────┘  │\n│         ▲                           ▲    │           ▲       │\n└─────────┼───────────────────────────┼────┼───────────┼───────┘\n          │ NATS (in-process)         │    │           │ Unix socket\n    ┌─────┴─────┐              ┌──────┴──┐ │     ┌─────┴──────┐\n    │  Agent A  │◄─────────────│ *.lua   │ │     │  sekiactl  │\n    │  Agent B  │   commands   │ scripts │◄┘     └────────────┘\n    └───────────┘              └─────────┘\n          │                  events ↑\n          └─────────────────────────┘\n```\n\n### Startup sequence\n\n1. Start embedded NATS with JetStream\n2. Create registry (subscribes to `sekia.registry` and `sekia.heartbeat.\u003e`)\n3. Start workflow engine, load `.lua` files, optionally start file watcher\n4. Start HTTP API on Unix socket\n5. Block on OS signal or stop channel\n6. Shutdown in reverse order\n\n### NATS subjects\n\n| Subject | Purpose |\n|---|---|\n| `sekia.registry` | Agent registration announcements |\n| `sekia.heartbeat.\u003cname\u003e` | Per-agent heartbeats (30s interval) |\n| `sekia.events.\u003csource\u003e` | Event publishing |\n| `sekia.commands.\u003cname\u003e` | Command delivery to agents |\n\n## Install\n\n### Homebrew (macOS/Linux)\n\n```bash\nbrew install sekia-ai/tap/sekia\n```\n\n### From source\n\n```bash\ngo install github.com/sekia-ai/sekia/cmd/sekiad@latest\ngo install github.com/sekia-ai/sekia/cmd/sekiactl@latest\ngo install github.com/sekia-ai/sekia/cmd/sekia-github@latest\ngo install github.com/sekia-ai/sekia/cmd/sekia-slack@latest\ngo install github.com/sekia-ai/sekia/cmd/sekia-linear@latest\ngo install github.com/sekia-ai/sekia/cmd/sekia-google@latest\ngo install github.com/sekia-ai/sekia/cmd/sekia-mcp@latest\n```\n\n### Docker\n\n```bash\n# Run the full stack\ndocker compose up\n\n# Or just the daemon\ndocker compose up sekiad\n```\n\nAgent credentials are read from environment variables. Copy `.env.example` to `.env` and fill in your tokens:\n\n```bash\ncp .env.example .env\n# Edit .env with your GITHUB_TOKEN, SLACK_BOT_TOKEN, etc.\ndocker compose up\n```\n\nIndividual images can be built with targets:\n\n```bash\ndocker build --target sekiad -t sekia/sekiad .\ndocker build --target sekia-github -t sekia/sekia-github .\n```\n\n## Getting started\n\n### Build\n\n```bash\ngo build ./cmd/sekiad ./cmd/sekiactl ./cmd/sekia-github ./cmd/sekia-slack ./cmd/sekia-linear ./cmd/sekia-google ./cmd/sekia-mcp\n```\n\n### Run the daemon\n\n```bash\n./sekiad\n```\n\n### Query status\n\n```bash\n./sekiactl status\n./sekiactl agents\n./sekiactl workflows\n```\n\n## Configuration\n\nsekia uses TOML config files searched in `/etc/sekia`, `~/.config/sekia`, and `.`. Environment variables with the `SEKIA_` prefix are also supported.\n\nDefaults:\n\n| Key | Default |\n|---|---|\n| `server.socket` | `~/.config/sekia/sekiad.sock` (or `$XDG_RUNTIME_DIR/sekia/sekiad.sock`) |\n| `server.listen` | `127.0.0.1:7600` |\n| `nats.embedded` | `true` |\n| `nats.data_dir` | `~/.local/share/sekia/nats` |\n| `workflows.dir` | `~/.config/sekia/workflows` |\n| `workflows.hot_reload` | `true` |\n| `workflows.verify_integrity` | `false` |\n| `ai.provider` | `anthropic` |\n| `ai.model` | `claude-sonnet-4-20250514` |\n| `ai.max_tokens` | `1024` |\n| `web.listen` | (empty — disabled) |\n\nSee [configs/sekia.toml](configs/sekia.toml) for an example.\n\n### Secrets Encryption\n\nSecret values in config files can be encrypted using [age](https://age-encryption.org/). Encrypted values are stored inline and decrypted transparently at startup.\n\n```bash\n# Generate a keypair (writes to ~/.config/sekia/age.key)\nsekiactl secrets keygen\n\n# Encrypt a value\nsekiactl secrets encrypt \"ghp_mytoken123\"\n# Output: ENC[YWdlLWVuY3J5cHRpb24...]\n```\n\nPaste the `ENC[...]` value into your config file:\n\n```toml\n[github]\ntoken = \"ENC[YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IF...]\"\n```\n\nThe decryption key can live off-machine — set `SEKIA_AGE_KEY` (raw key) or `SEKIA_AGE_KEY_FILE` (path) via your secrets manager or CI/CD pipeline. See [SECURITY.md](SECURITY.md) for details.\n\n## Web Dashboard\n\nsekia includes an embedded web dashboard for monitoring agents, workflows, and live events. Enable it by setting `web.listen`:\n\n```toml\n[web]\nlisten = \":8080\"\n```\n\nThen open `http://localhost:8080/web` in your browser. The dashboard shows:\n\n- **System status** — uptime, NATS status, agent/workflow counts\n- **Connected agents** — name, status, version, event/error counters, last heartbeat\n- **Loaded workflows** — name, handler count, event/error counters, patterns\n- **Live events** — real-time event stream via Server-Sent Events (SSE)\n\nStatus and agent/workflow panels auto-refresh every 5–10 seconds via htmx. The event stream updates in real-time. No external dependencies — htmx and Alpine.js are vendored and embedded in the binary.\n\nSecurity hardening is built in: `Content-Security-Policy`, `X-Frame-Options`, `X-Content-Type-Options`, and `Strict-Transport-Security` headers are set on every response. SSE connections are capped at 50 to prevent DoS. CSRF protection via double-submit cookie is enforced on all state-changing requests.\n\n## API\n\nThe daemon exposes an HTTP API over its Unix socket.\n\n| Endpoint | Description |\n|---|---|\n| `GET /api/v1/status` | Daemon status, uptime, agent count, workflow count |\n| `GET /api/v1/agents` | List registered agents with capabilities and stats |\n| `GET /api/v1/workflows` | List loaded workflows with handler patterns and stats |\n| `POST /api/v1/workflows/reload` | Reload all workflows from disk |\n\n## Agent SDK\n\nThe `pkg/agent` package provides an SDK for building agents that auto-register and send heartbeats.\n\n```go\npackage main\n\nimport (\n\t\"github.com/sekia-ai/sekia/pkg/agent\"\n\t\"github.com/sekia-ai/sekia/pkg/protocol\"\n)\n\nfunc main() {\n\ta, err := agent.New(agent.Config{\n\t\tRegistration: protocol.Registration{\n\t\t\tName:         \"my-agent\",\n\t\t\tVersion:      \"0.1.2\",\n\t\t\tCapabilities: []string{\"read\", \"write\"},\n\t\t\tCommands:     []string{\"sync\"},\n\t\t},\n\t\tNATSURLs: \"nats://127.0.0.1:4222\",\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer a.Close()\n\n\t// Use a.Conn() for custom NATS subscriptions\n\t// Call a.RecordEvent() / a.RecordError() to update counters\n}\n```\n\n## Workflows\n\nWorkflows are Lua scripts that react to events and send commands to agents. Place `.lua` files in the workflow directory (default `~/.config/sekia/workflows/`).\n\n```lua\n-- ~/.config/sekia/workflows/github_labeler.lua\n\nsekia.on(\"sekia.events.github\", function(event)\n    if event.type ~= \"github.issue.opened\" then return end\n\n    local title = string.lower(event.payload.title or \"\")\n    local label = \"triage\"\n    if string.find(title, \"bug\") then label = \"bug\" end\n\n    sekia.command(\"github-agent\", \"add_label\", {\n        owner  = event.payload.owner,\n        repo   = event.payload.repo,\n        number = event.payload.number,\n        label  = label,\n    })\n\n    sekia.log(\"info\", \"labeled issue #\" .. event.payload.number)\nend)\n```\n\n### Lua API\n\n| Function | Description |\n|---|---|\n| `sekia.on(pattern, handler)` | Register handler for NATS subject pattern (`*` and `\u003e` wildcards) |\n| `sekia.publish(subject, type, payload)` | Emit a new event |\n| `sekia.command(agent, command, payload)` | Send command to an agent |\n| `sekia.log(level, message)` | Log a message (`debug`, `info`, `warn`, `error`) |\n| `sekia.ai(prompt [, opts])` | Call an LLM and return the response text. Options: `model`, `max_tokens`, `temperature`, `system` |\n| `sekia.ai_json(prompt [, opts])` | Like `sekia.ai` but requests JSON and returns a parsed Lua table |\n| `sekia.name` | The workflow's name (derived from filename) |\n\nWorkflows run in a sandboxed Lua VM with only `base`, `table`, `string`, and `math` libraries available. Dangerous functions (`os`, `io`, `debug`, `dofile`, `load`) are removed.\n\nWhen `hot_reload` is enabled (default), editing or adding `.lua` files automatically reloads the affected workflows.\n\n### Workflow Integrity Verification\n\nWhen `workflows.verify_integrity` is enabled, the daemon verifies each `.lua` file against a SHA256 manifest (`workflows.sha256`) before loading it. This prevents tampered or unsigned workflows from executing.\n\n```toml\n[workflows]\nverify_integrity = true\n```\n\nGenerate the manifest with `sekiactl`:\n\n```bash\nsekiactl workflows sign\n# Signed 3 workflow(s) in ~/.config/sekia/workflows\n# a1b2c3...  github-labeler.lua\n# d4e5f6...  slack-responder.lua\n# 789abc...  linear-triage.lua\n```\n\nThe manifest uses `sha256sum`-compatible format. When hot-reload is enabled, updating the manifest file automatically triggers a full reload of all workflows.\n\n### AI-Powered Workflows\n\nWorkflows can call an LLM using `sekia.ai()` and `sekia.ai_json()`. Configure the AI provider in `sekia.toml`:\n\n```toml\n[ai]\n# api_key can also be set via SEKIA_AI_API_KEY env var\napi_key = \"\"\nmodel = \"claude-sonnet-4-20250514\"\nmax_tokens = 1024\n```\n\nBoth functions are synchronous and return `(result, nil)` on success or `(nil, error_string)` on failure. If no API key is configured, they return `nil, \"AI not configured\"`.\n\n`sekia.ai(prompt, opts)` returns the raw response text. `sekia.ai_json(prompt, opts)` requests a JSON response and parses it into a Lua table.\n\nOptions (all optional): `model`, `max_tokens`, `temperature`, `system`.\n\n**Example — AI issue classifier** ([configs/workflows/ai-issue-classifier.lua](configs/workflows/ai-issue-classifier.lua)):\n\n```lua\nsekia.on(\"sekia.events.github\", function(event)\n    if event.type ~= \"github.issue.opened\" then return end\n\n    local prompt = \"Classify this GitHub issue. Reply with exactly one word: bug, feature, question, or docs.\\n\\n\"\n        .. \"Title: \" .. (event.payload.title or \"\") .. \"\\n\"\n        .. \"Body: \" .. (event.payload.body or \"\")\n\n    local result, err = sekia.ai(prompt, {\n        max_tokens = 16,\n        temperature = 0,\n    })\n\n    if err then\n        sekia.log(\"error\", \"AI classification failed: \" .. err)\n        return\n    end\n\n    local label = string.lower(string.gsub(result, \"%s+\", \"\"))\n    sekia.command(\"github-agent\", \"add_label\", {\n        owner  = event.payload.owner,\n        repo   = event.payload.repo,\n        number = event.payload.number,\n        label  = label,\n    })\nend)\n```\n\n**Example — AI PR summary** ([configs/workflows/ai-pr-summary.lua](configs/workflows/ai-pr-summary.lua)):\n\n```lua\nsekia.on(\"sekia.events.github\", function(event)\n    if event.type ~= \"github.pr.opened\" then return end\n\n    local result, err = sekia.ai(\n        \"Write a brief one-paragraph summary of this pull request.\\n\\n\"\n            .. \"Title: \" .. (event.payload.title or \"\") .. \"\\n\"\n            .. \"Body: \" .. (event.payload.body or \"\"),\n        { system = \"You are a helpful code review assistant. Be concise and technical.\" }\n    )\n\n    if err then return end\n\n    sekia.command(\"github-agent\", \"create_comment\", {\n        owner  = event.payload.owner,\n        repo   = event.payload.repo,\n        number = event.payload.number,\n        body   = \"**AI Summary:** \" .. result,\n    })\nend)\n```\n\n## Agents\n\nEach agent is a standalone binary that connects to the daemon's NATS bus, publishes events from an external service, and executes commands dispatched by Lua workflows.\n\n### GitHub Agent\n\nIngests GitHub events via webhooks and/or REST API polling, and executes GitHub API commands.\n\n**Webhook mode** (default):\n\n```bash\nexport GITHUB_TOKEN=ghp_...\n./sekia-github\n```\n\nPoint your GitHub repository's webhook settings to `http://\u003chost\u003e:8080/webhook`. Optionally set `GITHUB_WEBHOOK_SECRET` to verify signatures.\n\n**Polling mode** — useful when the agent cannot receive inbound webhooks (e.g., behind a firewall or in local development). Both modes can run simultaneously.\n\n```toml\n# sekia-github.toml\n[poll]\nenabled = true\ninterval = \"30s\"\nrepos = [\"myorg/myrepo\"]\n```\n\nTo use polling only (no webhook server), set `webhook.listen = \"\"`.\n\n**Config**: [configs/sekia-github.toml](configs/sekia-github.toml). Env vars: `GITHUB_TOKEN`, `GITHUB_WEBHOOK_SECRET`, `SEKIA_NATS_URL`.\n\n**Events**:\n\n| GitHub Event | sekia Event Type | Source |\n|---|---|---|\n| Issue opened/closed/reopened/labeled/assigned | `github.issue.\u003caction\u003e` | Webhook |\n| Issue opened/closed | `github.issue.opened`, `github.issue.closed` | Polling |\n| Issue updated (any change) | `github.issue.updated` | Polling only |\n| PR opened/closed/merged/review_requested | `github.pr.\u003caction\u003e` | Webhook |\n| PR opened/closed/merged | `github.pr.opened`, `github.pr.closed`, `github.pr.merged` | Polling |\n| PR updated (any change) | `github.pr.updated` | Polling only |\n| Push | `github.push` | Webhook only |\n| Issue comment created | `github.comment.created` | Both |\n\nPolled events include `payload.polled = true` so workflows can distinguish them from webhook events if needed.\n\n**Commands**:\n\n| Command | Required Payload | Action |\n|---|---|---|\n| `add_label` | `owner`, `repo`, `number`, `label` | Add a label to an issue/PR |\n| `remove_label` | `owner`, `repo`, `number`, `label` | Remove a label |\n| `create_comment` | `owner`, `repo`, `number`, `body` | Post a comment |\n| `close_issue` | `owner`, `repo`, `number` | Close an issue |\n| `reopen_issue` | `owner`, `repo`, `number` | Reopen an issue |\n\n**Example workflow**: [configs/workflows/github-auto-label.lua](configs/workflows/github-auto-label.lua)\n\n---\n\n### Slack Agent\n\nConnects to Slack via [Socket Mode](https://api.slack.com/apis/socket-mode) (WebSocket). No public URL required.\n\n```bash\nexport SLACK_BOT_TOKEN=xoxb-...\nexport SLACK_APP_TOKEN=xapp-...\n./sekia-slack\n```\n\n**Setup**: Create a Slack app at [api.slack.com/apps](https://api.slack.com/apps) with Socket Mode enabled. Required bot token scopes: `chat:write`, `reactions:write`, `channels:history`, `groups:history`, `im:history`. Generate an app-level token with `connections:write` scope. Enable **Interactivity** in your app settings to receive button click events (no Request URL needed with Socket Mode).\n\n**Config**: [configs/sekia-slack.toml](configs/sekia-slack.toml). Env vars: `SLACK_BOT_TOKEN`, `SLACK_APP_TOKEN`, `SEKIA_NATS_URL`.\n\n**Events**:\n\n| Slack Event | sekia Event Type | Payload Fields |\n|---|---|---|\n| New message (not from bot) | `slack.message.received` | `channel`, `user`, `text`, `timestamp`, `thread_ts` (if threaded) |\n| Reaction added | `slack.reaction.added` | `user`, `reaction`, `channel`, `timestamp` |\n| Channel created | `slack.channel.created` | `channel_id`, `channel_name`, `creator` |\n| Message mentioning the bot | `slack.mention` | `channel`, `user`, `text`, `timestamp` |\n| Button clicked | `slack.action.button_clicked` | `action_id`, `value`, `block_id`, `user`, `user_name`, `channel`, `message_ts`, `message_text`, `trigger_id` |\n\n**Commands**:\n\n| Command | Required Payload | Action |\n|---|---|---|\n| `send_message` | `channel`, `text`, `blocks` (optional) | Post a message. When `blocks` is provided (array of [Block Kit](https://api.slack.com/block-kit) objects), sends a rich message with `text` as notification fallback |\n| `add_reaction` | `channel`, `timestamp`, `emoji` | Add a reaction to a message |\n| `send_reply` | `channel`, `thread_ts`, `text` | Reply in a thread |\n| `update_message` | `channel`, `timestamp`, `text`, `blocks` (optional) | Update an existing message. When `blocks` is provided, updates with rich Block Kit content |\n\n**Example workflow**: [configs/workflows/slack-auto-reply.lua](configs/workflows/slack-auto-reply.lua)\n\n```lua\nsekia.on(\"sekia.events.slack\", function(event)\n    if event.type ~= \"slack.mention\" then return end\n\n    sekia.command(\"slack-agent\", \"send_reply\", {\n        channel   = event.payload.channel,\n        thread_ts = event.payload.timestamp,\n        text      = \"Hi \u003c@\" .. event.payload.user .. \"\u003e, thanks for reaching out!\",\n    })\nend)\n```\n\n---\n\n### Linear Agent\n\nPolls the [Linear GraphQL API](https://developers.linear.app/docs/graphql/working-with-the-graphql-api) for updated issues and comments. No webhooks or public URL required.\n\n```bash\nexport LINEAR_API_KEY=lin_api_...\n./sekia-linear\n```\n\n**Setup**: Create a personal API key at [linear.app/settings/api](https://linear.app/settings/api).\n\n**Config**: [configs/sekia-linear.toml](configs/sekia-linear.toml). Env vars: `LINEAR_API_KEY`, `SEKIA_NATS_URL`.\n\n| Setting | Default | Description |\n|---|---|---|\n| `poll.interval` | `30s` | How often to poll Linear |\n| `poll.team_filter` | (empty) | Limit to a team key (e.g., `ENG`) |\n\n**Events**:\n\n| Trigger | sekia Event Type | Payload Fields |\n|---|---|---|\n| New issue (created since last poll) | `linear.issue.created` | `id`, `identifier`, `title`, `state`, `priority`, `team`, `url`, `assignee`, `labels` |\n| Issue updated | `linear.issue.updated` | (same as above) |\n| Issue moved to Done/Completed/Canceled | `linear.issue.completed` | (same as above) |\n| New comment | `linear.comment.created` | `id`, `body`, `author`, `issue_id`, `issue_identifier` |\n\n**Commands**:\n\n| Command | Required Payload | Action |\n|---|---|---|\n| `create_issue` | `team_id`, `title`, `description` (optional) | Create a new issue |\n| `update_issue` | `issue_id`, plus `state_id`/`assignee_id`/`priority` | Update an issue |\n| `create_comment` | `issue_id`, `body` | Add a comment to an issue |\n| `add_label` | `issue_id`, `label_id` | Add a label to an issue |\n\n**Example workflow**: [configs/workflows/linear-auto-triage.lua](configs/workflows/linear-auto-triage.lua)\n\n```lua\nsekia.on(\"sekia.events.linear\", function(event)\n    if event.type ~= \"linear.issue.created\" then return end\n\n    sekia.command(\"linear-agent\", \"create_comment\", {\n        issue_id = event.payload.id,\n        body     = \"Auto-triaged. Team: \" .. (event.payload.team or \"unknown\"),\n    })\nend)\n```\n\n---\n\n### Google Agent\n\nBridges Gmail and Google Calendar to the NATS event bus via Google REST APIs with OAuth2 authentication.\n\n```bash\n# First time: authorize via browser\nsekia-google auth --config configs/sekia-google.toml\n\n# Run the agent\n./sekia-google\n```\n\n**Setup**: Create OAuth credentials at [console.cloud.google.com/apis/credentials](https://console.cloud.google.com/apis/credentials) with application type \"Desktop app\". Run `sekia-google auth` to authorize via browser.\n\n**Config**: [configs/sekia-google.toml](configs/sekia-google.toml). Env vars: `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`, `GOOGLE_TOKEN_PATH`, `SEKIA_NATS_URL`.\n\n**Gmail Events**:\n\n| Trigger | sekia Event Type | Payload Fields |\n|---|---|---|\n| New message | `gmail.message.received` | `id`, `thread_id`, `message_id`, `from`, `to`, `subject`, `body`, `date`, `labels` |\n\n**Calendar Events**:\n\n| Trigger | sekia Event Type | Payload Fields |\n|---|---|---|\n| New event | `google.calendar.event.created` | `id`, `summary`, `description`, `location`, `start`, `end`, `organizer`, `attendees`, `html_link` |\n| Event updated | `google.calendar.event.updated` | (same as above) |\n| Event deleted | `google.calendar.event.deleted` | `id`, `summary`, `status` |\n| Event starting soon | `google.calendar.event.upcoming` | (same as created) + `minutes_until` |\n\n**Gmail Commands**:\n\n| Command | Required Payload | Action |\n|---|---|---|\n| `send_email` | `to`, `subject`, `body` | Send a new email |\n| `reply_email` | `thread_id`, `in_reply_to`, `to`, `subject`, `body` | Reply to an email |\n| `add_label` | `message_id`, `label` | Add a label to a message |\n| `remove_label` | `message_id`, `label` | Remove a label from a message |\n| `archive` | `message_id` | Archive a message (remove INBOX label) |\n| `trash` | `message_id` | Move a message to trash |\n| `untrash` | `message_id` | Move a trashed message back to inbox |\n| `delete` | `message_id` | Permanently delete a message |\n\n**Calendar Commands**:\n\n| Command | Required Payload | Action |\n|---|---|---|\n| `create_event` | `summary`, `start`, `end` | Create a calendar event |\n| `update_event` | `event_id`, plus optional fields | Update a calendar event |\n| `delete_event` | `event_id` | Delete a calendar event |\n\n**Example workflow**: [configs/workflows/google-calendar-notify.lua](configs/workflows/google-calendar-notify.lua)\n\n---\n\n### MCP Server\n\nExposes sekia capabilities to AI assistants (Claude Desktop, Claude Code, Cursor) via the [Model Context Protocol](https://modelcontextprotocol.io). Uses stdio transport — the MCP client launches `sekia-mcp` as a subprocess.\n\n```bash\n./sekia-mcp\n```\n\n**Config**: [configs/sekia-mcp.toml](configs/sekia-mcp.toml). Env vars: `SEKIA_NATS_URL`, `SEKIA_DAEMON_SOCKET`.\n\n**MCP Tools**:\n\n| Tool | Description |\n|---|---|\n| `get_status` | Daemon health, uptime, NATS status, agent/workflow counts |\n| `list_agents` | Connected agents with capabilities, commands, and heartbeat data |\n| `list_workflows` | Loaded Lua workflows with handler patterns and event/error counts |\n| `reload_workflows` | Hot-reload all .lua workflow files from disk |\n| `publish_event` | Emit a synthetic event onto the NATS bus to trigger workflows |\n| `send_command` | Send a command to a connected agent (Slack message, GitHub comment, etc.) |\n\n**Claude Desktop setup**: Add to your MCP settings (`~/Library/Application Support/Claude/claude_desktop_config.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"sekia\": {\n      \"command\": \"sekia-mcp\",\n      \"env\": {\n        \"SEKIA_NATS_URL\": \"nats://127.0.0.1:4222\",\n        \"SEKIA_DAEMON_SOCKET\": \"~/.config/sekia/sekiad.sock\"\n      }\n    }\n  }\n}\n```\n\n---\n\n## Cross-Agent Workflows\n\nThe real power of sekia is connecting agents together. Here's a workflow that posts to Slack when a GitHub issue is opened, and creates a Linear tracking issue:\n\n```lua\n-- ~/.config/sekia/workflows/issue-tracker.lua\n\nsekia.on(\"sekia.events.github\", function(event)\n    if event.type ~= \"github.issue.opened\" then return end\n\n    local title = event.payload.title\n    local url   = event.payload.url\n    local repo  = event.payload.repo\n\n    -- Notify the team in Slack\n    sekia.command(\"slack-agent\", \"send_message\", {\n        channel = \"C_ENGINEERING\",\n        text    = \"New issue in \" .. repo .. \": \" .. title .. \"\\n\" .. url,\n    })\n\n    -- Create a tracking issue in Linear\n    sekia.command(\"linear-agent\", \"create_issue\", {\n        team_id     = \"TEAM_ID_HERE\",\n        title       = \"[\" .. repo .. \"] \" .. title,\n        description = \"GitHub issue: \" .. url,\n    })\nend)\n```\n\n## Testing\n\n```bash\ngo test ./...\n```\n\nEach agent has end-to-end integration tests that start the full daemon with embedded NATS, connect the agent in-process, and verify the complete event-to-command flow through Lua workflows.\n\n## License\n\nApache 2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsekia-ai%2Fsekia","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsekia-ai%2Fsekia","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsekia-ai%2Fsekia/lists"}