From 3eece183be0bbe82768400d1bd41772c6a332a09 Mon Sep 17 00:00:00 2001 From: Sergio Alexander Florez Galeano Date: Fri, 12 Jun 2026 03:28:15 +0000 Subject: [PATCH] chore(skills): sync vendored dailybot pack to v1.7.0 (adds chat + teams) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary The repo-vendored copy of the Dailybot agent skill pack at `.agents/skills/dailybot/` was stuck at v1.3.0 — months behind the upstream `DailybotHQ/agent-skill` release, missing **every sub-skill added since v1.3.0**, including: - `dailybot-chat` (NEW in upstream v1.7.0 — Slack/Teams/Discord/Google Chat bot messages with report-style threads and in-place edits) - `dailybot-teams` (the team-name resolver that `dailybot-kudos` and `dailybot-chat` delegate to) - A rewritten `dailybot-forms` (full lifecycle: list / submit / get / update / transition / delete; previously only list+submit) - A rewritten `dailybot-kudos` (team-targeted kudos; previously user-only) - A rewritten `dailybot-report` with hook enforcement (CLI 1.12.0+) This commit replaces the entire `.agents/skills/dailybot/` subtree with the published `v1.7.0` content (cloned from `git@github.com:DailybotHQ/agent-skill.git`, tag `v1.7.0`) so that agents working inside *this* repo see the same skill an end user gets from `npx skills add DailybotHQ/agent-skill`. It also cleans up two stale references that pointed at the legacy `dailybot-progress-report` skill (which was replaced by the full pack in commit 0068638 but the docs were never updated). ## Change Log - `.agents/skills/dailybot/`: bumped router version 1.3.0 → **1.7.0**, 9 sub-skills (was 7), all SKILL.md files refreshed from the upstream v1.7.0 tag. Diff: 1023 insertions / 161 deletions across 11 SKILL.md files + the shared http-fallback table. - `.agents/docs/skills_agents_catalog.md`: - The old `dailybot-progress-report` row replaced with a full sub-section listing all nine Dailybot sub-skills + the path to each `SKILL.md`, mirroring the structure of the rest of the catalog. - The "Quick-Reference Decision Table" updated so "Report what you just shipped" now points at `dailybot-report` (not the legacy `dailybot-progress-report`) and gained four new rows for chat, kudos, checkin, and forms. - `AGENTS.md`: - The "Agent Progress Reporting" section now links `.agents/skills/dailybot/report/SKILL.md` (live) instead of the legacy `.agents/skills/dailybot-progress-report/SKILL.md` (404). - The Skills & Agents System bullet now enumerates the nine Dailybot sub-skills the vendored pack ships. ## Validation - `grep -rn dailybot-progress-report AGENTS.md .agents/` → only the legitimate "replaces the legacy ..." migration note remains. - All 9 `dailybot-*` slugs resolve to a file that exists on disk (checked end-to-end). - `ruff check dailybot_cli tests` + `mypy dailybot_cli` clean (this PR is docs-only; no source touched). ## Risks - None for runtime. `.agents/skills/dailybot/` is consumed only by agents working inside this repo (via the `.claude/` symlink) — no end-user code depends on it. ## Dogfood note Validated by Claude (Cursor) in a five-step run through the v1.7.0 pack (health → messages → teams → chat → report) before opening this PR. The `dailybot chat send` exercised was authenticated with the login Bearer token shipped in `dailybot-cli 1.13.0`. Co-authored-by: Cursor --- .agents/docs/skills_agents_catalog.md | 24 +- .agents/skills/dailybot/SKILL.md | 114 +++- .agents/skills/dailybot/chat/SKILL.md | 484 ++++++++++++++ .agents/skills/dailybot/checkin/SKILL.md | 2 +- .agents/skills/dailybot/email/SKILL.md | 2 +- .agents/skills/dailybot/forms/SKILL.md | 616 +++++++++++++++--- .../dailybot/forms/_custom-template/SKILL.md | 129 ++++ .agents/skills/dailybot/health/SKILL.md | 2 +- .agents/skills/dailybot/kudos/SKILL.md | 307 +++++++-- .agents/skills/dailybot/messages/SKILL.md | 2 +- .agents/skills/dailybot/report/SKILL.md | 109 +++- .agents/skills/dailybot/report/hooks.md | 154 +++++ .agents/skills/dailybot/report/triggers.md | 7 + .../skills/dailybot/shared/http-fallback.md | 1 + .agents/skills/dailybot/teams/SKILL.md | 231 +++++++ AGENTS.md | 4 +- 16 files changed, 2026 insertions(+), 162 deletions(-) create mode 100644 .agents/skills/dailybot/chat/SKILL.md create mode 100644 .agents/skills/dailybot/forms/_custom-template/SKILL.md create mode 100644 .agents/skills/dailybot/report/hooks.md create mode 100644 .agents/skills/dailybot/teams/SKILL.md diff --git a/.agents/docs/skills_agents_catalog.md b/.agents/docs/skills_agents_catalog.md index 6dbfc39..66862c2 100644 --- a/.agents/docs/skills_agents_catalog.md +++ b/.agents/docs/skills_agents_catalog.md @@ -14,7 +14,23 @@ Slash commands. Invoked as `/` (Claude Code) or `#` (Codex/Cursor/Ge | `release-prep` | [`skills/release-prep/SKILL.md`](../skills/release-prep/SKILL.md) | Pre-tag checklist + version bump for cutting a release | | `dependency-add` | [`skills/dependency-add/SKILL.md`](../skills/dependency-add/SKILL.md) | Adding a Python dep (pyproject + Homebrew formula sync) | | `doc-edit` | [`skills/doc-edit/SKILL.md`](../skills/doc-edit/SKILL.md) | Updating docs without touching code | -| `dailybot-progress-report` | [`skills/dailybot-progress-report/SKILL.md`](../skills/dailybot-progress-report/SKILL.md) | Reporting agent progress through the CLI itself | + + +### Dailybot agent skill pack (vendored from [`DailybotHQ/agent-skill`](https://github.com/DailybotHQ/agent-skill)) + +The full pack lives under [`.agents/skills/dailybot/`](../skills/dailybot/) (router + nine sub-skills). The router auto-routes by intent — read [`skills/dailybot/SKILL.md`](../skills/dailybot/SKILL.md) and let it pick the right sub-skill. Direct sub-skill entry points: + +| Slug | Procedure | Use when | +|------|-----------|----------| +| `dailybot-report` | [`skills/dailybot/report/SKILL.md`](../skills/dailybot/report/SKILL.md) | Reporting agent progress through the CLI itself (replaces the legacy `dailybot-progress-report` skill) | +| `dailybot-messages` | [`skills/dailybot/messages/SKILL.md`](../skills/dailybot/messages/SKILL.md) | Polling for instructions sent to this agent by teammates | +| `dailybot-health` | [`skills/dailybot/health/SKILL.md`](../skills/dailybot/health/SKILL.md) | Announcing online/offline status on long sessions | +| `dailybot-email` | [`skills/dailybot/email/SKILL.md`](../skills/dailybot/email/SKILL.md) | Sending email on the agent's behalf (with mandatory pre-send safety checks) | +| `dailybot-checkin` | [`skills/dailybot/checkin/SKILL.md`](../skills/dailybot/checkin/SKILL.md) | Listing and completing pending check-ins (user-scoped) | +| `dailybot-kudos` | [`skills/dailybot/kudos/SKILL.md`](../skills/dailybot/kudos/SKILL.md) | Giving kudos to a teammate or a whole team | +| `dailybot-teams` | [`skills/dailybot/teams/SKILL.md`](../skills/dailybot/teams/SKILL.md) | Listing / resolving teams (the resolver `dailybot-kudos` and `dailybot-chat` delegate to) | +| `dailybot-forms` | [`skills/dailybot/forms/SKILL.md`](../skills/dailybot/forms/SKILL.md) | Listing, submitting, updating, or transitioning form responses | +| `dailybot-chat` | [`skills/dailybot/chat/SKILL.md`](../skills/dailybot/chat/SKILL.md) | Sending / editing Dailybot bot messages on Slack / Teams / Discord / Google Chat (DMs, channels, teams; report-style threads; in-place edits). Requires `dailybot-cli >= 1.13.0` | ## Agents @@ -38,7 +54,11 @@ Persona definitions. Use these as the system prompt / role when spawning a sub-a | Update README / docs only | `doc-edit` | `docs-writer` | | Add `httpx-retries` to deps | `dependency-add` | `cli-developer` | | Cut v0.4.13 | `release-prep` | `release-manager` | -| Report what you just shipped | `dailybot-progress-report` | (any) | +| Report what you just shipped | `dailybot-report` | (any) | +| Send a Slack/Teams/Discord/Google Chat message (DM, channel, team; report-style threads) | `dailybot-chat` | (any) | +| Recognize a teammate or a whole team | `dailybot-kudos` | (any) | +| Complete a pending check-in / standup | `dailybot-checkin` | (any) | +| Submit / transition / update a form response | `dailybot-forms` | (any) | ## Conventions diff --git a/.agents/skills/dailybot/SKILL.md b/.agents/skills/dailybot/SKILL.md index e12ada4..819d411 100644 --- a/.agents/skills/dailybot/SKILL.md +++ b/.agents/skills/dailybot/SKILL.md @@ -1,7 +1,7 @@ --- name: dailybot -description: Official Dailybot agent skill pack — report progress, check messages, send emails, announce agent status, complete check-ins, give kudos, and submit forms. Routes to the right sub-skill based on intent. Use when the developer mentions Dailybot or wants to interact with their team. -version: "1.3.0" +description: Official Dailybot agent skill pack — report progress, check messages, send emails, announce agent status, complete check-ins, give kudos (to users or teams), resolve teams, run the full forms lifecycle (list, submit, update, transition between workflow states), and send/edit chat messages on the team's Slack/Teams/Discord/Google Chat (including report-style threads). Routes to the right sub-skill based on intent. Use when the developer mentions Dailybot or wants to interact with their team. +version: "1.7.0" documentation_url: https://api.dailybot.com/skill.md user-invocable: true metadata: {"openclaw":{"emoji":"📡","homepage":"https://dailybot.com","requires":{"anyBins":["dailybot","curl"]},"primaryEnv":"DAILYBOT_API_KEY","install":[{"id":"cli-install-script","kind":"download","url":"https://cli.dailybot.com/install.sh","label":"Install Dailybot CLI (official script — preferred on Linux/macOS)"},{"id":"pip","kind":"pip","package":"dailybot-cli","bins":["dailybot"],"label":"Install Dailybot CLI via pip (fallback if binary fails)"}]}} @@ -21,17 +21,19 @@ This is the canonical, first-party integration. Source of truth: ## What it does -Seven coordinated capabilities, with smart routing between them: +Nine coordinated capabilities, with smart routing between them: | Capability | Sub-skill | When it fires | |------------|-----------|---------------| | **Progress reports** | `dailybot-report` | After meaningful work — a completed task, or a batch of edits to 3+ files | | **Message polling** | `dailybot-messages` | Session start, idle moments, or when the developer asks "what should I work on?" | | **Email** | `dailybot-email` | Explicit user request, with mandatory pre-send safety checks | +| **Chat** | `dailybot-chat` | Developer wants to send / edit a bot message on Slack, Teams, Discord, or Google Chat — to a channel, DMs, or whole team. Supports report-style threads (headline + replies in one call) and editing the parent or any reply afterward | | **Health & status** | `dailybot-health` | Long-running sessions; periodic heartbeats | | **Check-ins** | `dailybot-checkin` | Developer asks to complete a standup or fill in a pending check-in | -| **Kudos** | `dailybot-kudos` | Developer wants to recognize a teammate's contribution | -| **Forms** | `dailybot-forms` | Developer wants to list or submit a form response (surveys, retros, pulse checks) | +| **Kudos** | `dailybot-kudos` | Developer wants to recognize a teammate or a whole team's contribution | +| **Teams** | `dailybot-teams` | List teams, inspect members, or resolve a team name → UUID (used as a resolver by other skills) | +| **Forms** | `dailybot-forms` | Developer wants to list, submit, update, or transition forms — including workflow-state forms with audience permissions | ## Install @@ -43,6 +45,94 @@ Six install methods are supported (skills.sh CLI, OpenClaw native, git clone + `setup.sh`, conversational, manual per-agent, and HTTP-only fallback). Full guide: [`docs/INSTALLATION.md`](https://github.com/DailybotHQ/agent-skill/blob/main/docs/INSTALLATION.md). +## Required Dailybot CLI version + +> **Minimum:** `dailybot-cli >= 1.10.0` (released **2026-05-26**, MIT-licensed, +> [pypi.org/project/dailybot-cli/1.10.0/](https://pypi.org/project/dailybot-cli/1.10.0/)). +> +> Requires **Python >= 3.10**. The 1.10.0 wheel is `py3-none-any` (pure Python). +> +> **`1.11.0` enhancement (optional):** `dailybot agent update` echoes the +> report's placement link as a `View:` line. Older CLIs still report fine — +> the link is always in the API response body, just not printed — so this is +> not a hard floor. See [`report/SKILL.md`](report/SKILL.md) Step 7. +> +> **`1.12.0` enhancement (recommended):** the `dailybot hook` command group +> (`session-start` / `post-commit` / `activity` / `stop` / `dismiss`) lets +> the agent harness remind the model **deterministically** to report +> unreported work — including non-commit work — via lifecycle hooks, backed +> by a local per-repo ledger. This is what makes reporting fully autonomous. +> Not a hard floor either: below 1.12.0 the prompt triggers still work. See +> [`report/hooks.md`](report/hooks.md) and the +> [CLI hook docs](https://github.com/DailybotHQ/cli/blob/main/docs/AGENT_HOOKS.md). +> +> **`1.13.0` floor for `dailybot-chat`** ([PyPI](https://pypi.org/project/dailybot-cli/1.13.0/), +> released **2026-06-12**): the `dailybot chat send` / `chat update` +> command group first ships in 1.13.0, together with login-Bearer auth on +> `/v1/send-message/` (so the developer doesn't need an org API key to +> send a chat message), report-style threads via `--thread-message` +> (≤10 per call), and individually-editable thread reply ids. The +> `dailybot-chat` sub-skill requires this minimum; the other sub-skills +> are unaffected. See [`chat/SKILL.md`](chat/SKILL.md). + +### Why this minimum + +The `dailybot-forms`, `dailybot-teams`, and `dailybot-kudos` sub-skills depend on +CLI surface that **first ships in 1.10.0**: + +- `dailybot form get` / `form responses` / `form response get` — inspect forms and prior responses. +- `dailybot form update` / `form transition` / `form delete` — drive a response through its workflow. +- `dailybot team list` / `team get [--with-members]` — role-scoped team reads. +- `dailybot kudos give --team ""` — team-targeted kudos (caller excluded from the expansion). +- Standardized user-scoped exit codes (`0` / `2` / `3` / `4` / `5` / `6` / `7`). +- `--json` 4xx errors include the structured `code` field (`form_response_change_state_forbidden`, `final_state_locked`, `no_valid_team`, …) so agents can pattern-match without parsing prose. + +CLI versions below 1.10.0 only expose `form list` + `form submit` and user-only +kudos; the sub-skills detect the gap and fail cleanly (exit-code messaging will +ask the developer to upgrade). + +### Checking the installed version + +```bash +# Single-line, scriptable +dailybot --version +# → dailybot 1.10.0 (Python 3.12.4) + +# Multi-line panel: version, Python runtime, install path, release notes link +dailybot version + +# Same panel + queries PyPI to tell you whether a newer version exists +dailybot version --check +``` + +### Upgrading a stale install + +```bash +dailybot upgrade +``` + +The CLI auto-detects how it was installed (`pipx` / `uv tool` / `pip` / +Homebrew / Linux binary / editable dev) and either runs the right command in a +subprocess or prints the exact command for installs the CLI shouldn't drive. +`dailybot upgrade --dry-run` previews without executing. + +If the developer is below 1.10.0, ask them to run `dailybot upgrade` once, +then resume. Do not retry CLI commands in a loop while the upgrade is pending. + +### Direct install commands + +| Channel | Command | +|---------|---------| +| pip | `pip install 'dailybot-cli>=1.10.0'` | +| Homebrew | `brew install dailybothq/tap/dailybot` | +| Universal installer (Linux / macOS / WSL2 / Git Bash) | `curl -sSL https://cli.dailybot.com/install.sh \| bash` | +| Windows PowerShell (when WSL2 / Git Bash unavailable) | `irm https://cli.dailybot.com/install.ps1 \| iex` | + +The universal installer auto-detects the OS and routes to Homebrew on macOS, +the prebuilt binary on Linux x86_64, or pipx / uv tool / pip --user elsewhere. +Full safety story (SHA-256 sidecar, cross-origin diff, optional cosign): see +[`shared/auth.md`](shared/auth.md). + ## Why use the official skill - **First-party.** Built by the Dailybot team and kept in sync with the @@ -87,20 +177,30 @@ the full step-by-step workflow. | "email this to Alice", "send an email", "send a summary to the team" | **Email** → read [`email/SKILL.md`](email/SKILL.md) | | "go online", "announce status", "health check" | **Health** → read [`health/SKILL.md`](health/SKILL.md) | | "complete my check-in", "fill in my standup", "answer my dailybot", "any pending check-ins?" | **Checkin** → read [`checkin/SKILL.md`](checkin/SKILL.md) | -| "give kudos to Jane", "recognize Alice for the PR review", "thank Bob for the help" | **Kudos** → read [`kudos/SKILL.md`](kudos/SKILL.md) | -| "list my forms", "fill out the feedback survey", "submit the retro form", "what forms do I have?" | **Forms** → read [`forms/SKILL.md`](forms/SKILL.md) | +| "give kudos to Jane", "recognize Alice", "kudos al equipo Engineering", "felicita al team de QA" | **Kudos** → read [`kudos/SKILL.md`](kudos/SKILL.md) | +| "list my teams", "who's in QA?", "resolve the Engineering team", or another skill needs a team UUID | **Teams** → read [`teams/SKILL.md`](teams/SKILL.md) | +| "list my forms", "submit the retro form", "continue my release-form draft", "transition the release to released", "show me the last form response" | **Forms** → read [`forms/SKILL.md`](forms/SKILL.md) | +| "send a Slack message", "DM Sergio in chat", "post the deploy report to #releases (with a thread)", "edit that chat message I just sent", "ping the Engineering team in chat" | **Chat** → read [`chat/SKILL.md`](chat/SKILL.md) | ### Auto-activation (no explicit request) | Situation | Route to | |-----------|----------| | You completed a task/subtask, or edited 3+ files | **Report** → read [`report/SKILL.md`](report/SKILL.md) | +| A Dailybot hook reminder was injected into your context ("commits have landed…" / "sustained work without a progress report…") | **Report** → read [`report/SKILL.md`](report/SKILL.md); if nothing significant happened, run `dailybot hook dismiss` instead — never ignore the reminder silently | | Starting a long work session or idle for 15+ minutes | **Health** → read [`health/SKILL.md`](health/SKILL.md) | **Disambiguation:** "check in with the team" → **Health**; "complete my check-in" or "fill in standup" → **Checkin**. The word "check-in" alone with no verb defaults to **Checkin** (the structured questionnaire). +**Report vs Chat.** "Report this to Dailybot" / "tell my team what we built" +defaults to **Report** (dashboard). Switch to **Chat** only when the +developer explicitly mentions a chat platform / channel / channel id, or +says "send a message" / "ping in chat" / "post to #channel". Chat is +externally visible to other humans on the connected platform; report goes +to the Dailybot dashboard. + If the intent is ambiguous, default to **Report** — it's the most common use case. diff --git a/.agents/skills/dailybot/chat/SKILL.md b/.agents/skills/dailybot/chat/SKILL.md new file mode 100644 index 0000000..dc98b44 --- /dev/null +++ b/.agents/skills/dailybot/chat/SKILL.md @@ -0,0 +1,484 @@ +--- +name: dailybot-chat +description: Send and edit Dailybot bot messages on the team's connected chat platform (Slack, Microsoft Teams, Discord, Google Chat) — to user DMs, channels, or whole teams. Supports report-style threads (one headline + replies, in one call) and editing the parent or any reply afterward. Use when the developer says "send a message to my Slack channel", "ping the team in chat", "post the deploy report to #releases", or wants to update a previously sent bot message. Works headless for agents. +version: "1.7.0" +documentation_url: https://api.dailybot.com/skill.md +user-invocable: true +metadata: {"openclaw":{"emoji":"💬","homepage":"https://dailybot.com","requires":{"anyBins":["dailybot","curl"]},"primaryEnv":"DAILYBOT_API_KEY","install":[{"id":"cli-install-script","kind":"download","url":"https://cli.dailybot.com/install.sh","label":"Install Dailybot CLI (official script — preferred on Linux/macOS)"},{"id":"pip","kind":"pip","package":"dailybot-cli","bins":["dailybot"],"label":"Install Dailybot CLI via pip (fallback if binary fails)"}]}} +allowed-tools: Bash, Read, Grep, Glob +--- + +# Dailybot Chat + +> **Requires `dailybot-cli >= 1.13.0`** ([PyPI](https://pypi.org/project/dailybot-cli/1.13.0/), released 2026-06-12). 1.13.0 is what first shipped the `dailybot chat send` / `chat update` command group, the `--thread-message` flag (≤10 replies per call, each independently editable), and the login-Bearer auth path on `/v1/send-message/` (so the developer can send without an org API key). Below 1.13.0, the `dailybot chat` group does not exist — ask the developer to run `dailybot upgrade`. See [`../SKILL.md` § Required Dailybot CLI version](../SKILL.md#required-dailybot-cli-version) for install commands and version-check tooling. + +You send **Dailybot bot messages** on the developer's behalf to the organization's connected chat platform (Slack, Microsoft Teams, Discord, Google Chat) — to user DMs, channels, or whole teams (expanded to member DMs server-side). This skill is the right surface for: + +- A short heads-up to a channel ("deploy started") +- A **report-style post**: a short headline in the channel + the full detail in **its thread**, in a single call (keeps the channel clean, groups the context, looks like a real human update) +- Pinging one or several teammates by DM +- Editing a previously sent message in place — including any individual thread reply + +It is **not**: + +- `dailybot-report` — that posts progress updates to the Dailybot dashboard (no Slack/Teams delivery by default). +- `dailybot-email` — that sends transactional email. +- `dailybot-messages` — that polls inbound agent-to-agent messages. + +If the developer wants to "tell the team in Dailybot" generically, prefer `dailybot-report`. Route to `dailybot-chat` only when they explicitly mention chat / Slack / Teams / Discord / Google Chat, or a channel id / channel name, or want a message visible inside the chat tool itself. + +--- + +## When to Use + +Trigger phrases the agent should recognize: + +**Send (channels / users / teams):** +- "send a Slack message to #releases", "post to channel C0123" +- "DM Carolina that the build is green", "ping Sergio Florez in chat" +- "broadcast this to the Engineering team in Slack" +- "post a deploy summary to #releases with the changelog as a thread" +- "send a chat message to the QA team" + +**Edit / update a previous message:** +- "update the deploy message to say done" +- "edit that Slack message I just sent" +- "change the second thread reply to say rolled back" + +**Do not** send chat messages autonomously without the developer's explicit request — chat messages are visible to other people and carry the developer's own identity (with a login session) or the bot identity (with an API key). Always confirm before sending unless the developer pre-approved a flow (`--yes`-style intent). + +--- + +## Auth model — both login Bearer and org API key are supported + +`POST /v1/send-message/` accepts either auth, and the CLI uses whichever is configured: + +- **Login Bearer token** (`dailybot login` — preferred for human-driven sends): the message is delivered **as the logged-in user**, scoped by their role in their own org. Admins/managers reach anyone / any connected channel / any team; team members reach teammates, public channels, and teams they belong to; guests reach only themselves. Per-token CLI rate limits apply. +- **Organization API key** (`dailybot config key=...` or `DAILYBOT_API_KEY`): org-wide scope, not role-restricted, not per-token throttled — the canonical agent path. + +The client picks the **API key first** if one is set, else falls back to the Bearer. The `update` call follows the same auth as `send`. + +If the developer is unauthenticated, read [`../shared/auth.md`](../shared/auth.md) and surface either path. Do not push the developer to create an API key just to send one chat message — `dailybot login` is enough for a human. + +--- + +## Step 1 — Verify Setup + +Read and follow [`../shared/auth.md`](../shared/auth.md). It covers CLI installation, login (email OTP), API key setup, and agent profile configuration. + +Then verify the CLI sees a usable session: + +```bash +dailybot status --auth 2>&1 +``` + +If auth fails or the developer declines, **skip and continue with your primary task** — chat messages must never block work (see the non-blocking rule below). + +--- + +## Step 2 — Resolve the Target(s) + +The CLI targeting flags **only accept ids/emails, never free-form names**: + +| Flag | Short | Accepts | +|------|-------|---------| +| `--user` | `-u` | User UUID, email, or chat-platform external id | +| `--channel` | `-c` | Channel id from the chat platform (Slack `C0…`, Teams channel id, Discord channel id, Google Chat space) | +| `--team` | `-t` | Team UUID (expanded server-side to member DMs) | + +At least one of `--user / --channel / --team` is required. They can be repeated and combined. + +### 2a — User by name → resolve via `dailybot user list` + +When the developer references a teammate by name ("send to Sergio Florez"), resolve the name to a UUID with the organization directory: + +```bash +dailybot user list --json +``` + +This returns active members with their names and UUIDs (emails are intentionally hidden — PII). Pick the unambiguous match; if multiple names match, surface them and ask the developer to disambiguate. Never guess. + +### 2b — Team by name → delegate to `dailybot-teams` + +For a team-by-name target ("send a message to the QA team"), delegate to the `dailybot-teams` skill exactly as `dailybot-kudos` does — see [`../teams/SKILL.md`](../teams/SKILL.md) for the canonical resolver. The same scoping-aware error message applies if the team is not visible to the caller. + +### 2c — Channel by id (always) + +Channels are always referenced by their platform external id (Slack `C0123456789`, Teams `19:abc@thread.tacv2`, Discord numeric id, Google Chat `spaces/AAA…`). The CLI does not resolve channels by display name — ask the developer to paste the id if they only know the name. (Tip for Slack: right-click the channel → *View channel details* → bottom shows the id.) + +### 2d — Always confirm before sending + +Show the resolved targets + the message body + (for team targets) the expanded receiver count, then ask "Send? (yes / edit / cancel)". Chat sends are externally visible — do not skip confirmation unless the developer has already approved this exact send. + +--- + +## Step 3 — Choose Execution Path + +```bash +command -v dailybot +``` + +- **CLI found** → Step 4A +- **CLI not found** → Step 4B (HTTP fallback; see [`../shared/http-fallback.md`](../shared/http-fallback.md) for base patterns) + +--- + +## Step 4A — Send via CLI + +> **Timeout:** Allow at least 30 seconds for CLI commands to complete. Do not use a shorter timeout. + +### Single message to a channel + +```bash +dailybot chat send -c C0123 -m "Deploy v2.4 started 🚀" +``` + +### DM one or several people (by UUID, resolved in Step 2a) + +```bash +dailybot chat send \ + -u 294bf2cc-e3c7-401d-a1d6-bf20aa64bb33 \ + -u 8a1b9c1e-9d7e-4f0e-9aa1-7c5e4d0a5e0c \ + -m "Standup in 10 min — please join the Slack huddle" +``` + +### To a whole team (expanded to member DMs) + +```bash +dailybot chat send -t -m "Survey is open until Friday" +``` + +### Report style — headline + the detail in its thread, in ONE call + +This is the canonical pattern for any "report" the developer wants visible in chat (deploys, releases, incidents, status changes). The response returns the **parent `bot_message_id` plus one id per reply**, all individually editable later. + +```bash +dailybot chat send -c C0123 -m "🚀 Release v2.4 shipped" \ + --thread-message "Changelog: …" \ + --thread-message "Rollout: 100% at 14:30 UTC" \ + --thread-message "Next deploy window: tomorrow 10 AM" +``` + +Constraints: +- `--thread-message` is repeatable up to **10 replies per call** (validated client-side). +- Each reply inherits the parent's recipients — replies do not target their own users/channels/teams. +- Thread rendering: native on Slack (channels + DMs). On Teams/Discord/Google Chat threads work in channels and arrive **flat in DMs** (the replies always land, never dropped). + +### Custom Slack identity (Slack only) + +```bash +dailybot chat send -c C0123 -m "Build #421 ✅" \ + --bot-name "Release Bot" --bot-icon-emoji ":rocket:" \ + --link-button "Open report::https://app.dailybot.com/r/421" +``` + +`--bot-icon-url` (https-only) and `--bot-icon-emoji` are mutually exclusive. Custom identity requires the Slack `chat:write.customize` scope on the Dailybot app — without it Slack uses the default identity and the API still returns `ok: true`. On Teams/Discord/Google Chat, custom identity is silently ignored. + +### Ephemeral message (Slack only; only the recipient sees it) + +```bash +dailybot chat send -u ana@co.com -m "Heads up: build broke" --ephemeral +``` + +Ephemeral needs a `--user` target. A channel-only ephemeral send is skipped by the platform — the CLI warns up front. + +### Buttons + +```bash +# Link button (jumps to a URL) +--link-button "View PR::https://github.com/org/repo/pull/123" + +# Interactive button (server-side action; value is what's sent on click) +--button "Approve::approve-release-v2.4" +``` + +Both flags are repeatable. + +### Headless / agent use — capture the ids in JSON + +```bash +RESPONSE=$(dailybot chat send -c C0123 -m "Deploying…" \ + --thread-message "Started at 14:00 UTC" --json) + +PARENT=$(echo "$RESPONSE" | jq -r .bot_message_id) +REPLY1=$(echo "$RESPONSE" | jq -r '.thread_responses[0]') +``` + +`--json` prints the raw API response (`{ "bot_message_id": "", "thread_responses": ["", …] }`) to stdout — no panels, no prompts. Pair it with `--yes`-style intent (i.e. you've already confirmed with the developer) for fully headless flows. + +### Raw payload escape hatch (forward-compat) + +For multi-part `messages`, rich `thread_responses` objects, or any future API field the building flags do not expose yet: + +```bash +dailybot chat send --payload-json '{ + "target_channels": ["C0123"], + "messages": [{"message": "Deploy started"}], + "thread_responses": [{"message": "Changelog: …"}] +}' +``` + +`--payload-json` bypasses the structured flags and is forward-compatible with anything the API accepts. + +### Update a previously sent message (parent **or** any thread reply) + +A reply id is just another `bot_message_id` — `chat update` edits either: + +```bash +# Edit the parent (the channel post itself) +dailybot chat update "$PARENT" -c C0123 -m "Deploy done ✅" + +# Edit one of the thread replies +dailybot chat update "$REPLY1" -c C0123 -m "Started at 14:00 UTC (took 6 min)" +``` + +The chat platform keeps the message's original bot name/avatar on an edit, so identity flags (`--bot-name`/`--bot-icon-*`) are ignored when updating. Pass the same channel id you originally sent to. + +### CLI flag cheat sheet + +| Flag | Short | Description | +|------|-------|-------------| +| `--user` | `-u` | Target user by UUID, email, or platform external id (repeatable) | +| `--channel` | `-c` | Target channel id (repeatable) | +| `--team` | `-t` | Target team UUID; expanded to members as DMs (repeatable) | +| `--text` | `-m` | Message text (markdown where supported) | +| `--image-url` | `-i` | Public image URL to attach | +| `--link-button` | | `"Label::https://url"` (repeatable) | +| `--button` | | `"Label::value"` interactive button (repeatable) | +| `--thread-message` | | Reply posted in the parent's thread (repeatable; max 10) | +| `--thread` | | Reply into an existing platform thread id (channels) | +| `--channel-type` | | `channel` / `private_channel` / `group_chat` / `direct_message` | +| `--bot-name` | | Custom bot display name (Slack only) | +| `--bot-icon-url` | | Custom bot avatar URL, https (Slack only) | +| `--bot-icon-emoji` | | Custom bot avatar emoji (Slack only) | +| `--ephemeral` | | Send ephemerally — recipient-only (Slack; needs `--user`) | +| `--skip-time-off` | | Skip users currently flagged as away / on time-off | +| `--metadata` | `-d` | JSON metadata to attach | +| `--payload-json` | | Raw request body JSON (full API control; bypasses building flags) | +| `--json` | | Emit the raw API response as JSON to stdout (headless) | +| `--profile` | `-p` | Agent profile from `agents.json` (rarely needed for chat) | + +--- + +## Step 4B — Send via HTTP API (CLI unavailable) + +See [`../shared/http-fallback.md`](../shared/http-fallback.md) for base patterns. **`POST /v1/send-message/` accepts either `X-API-KEY` or `Authorization: Bearer`** — use whichever you have. + +### Channel send with a thread (parent + 2 replies in one call) + +```bash +curl -s -X POST https://api.dailybot.com/v1/send-message/ \ + -H "X-API-KEY: $DAILYBOT_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "target_channels": ["C0123"], + "message": "🚀 Release v2.4 shipped", + "thread_responses": [ + {"message": "Changelog: …"}, + {"message": "Rollout: 100% at 14:30 UTC"} + ] + }' +``` + +Response: + +```json +{ + "bot_message_id": "$db/cd626a24-...", + "thread_responses": [ + "$db/22aca052-...", + "$db/1f57b5fc-..." + ] +} +``` + +### DM a user (Bearer path — login session) + +```bash +curl -s -X POST https://api.dailybot.com/v1/send-message/ \ + -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "target_users": ["294bf2cc-e3c7-401d-a1d6-bf20aa64bb33"], + "message": "Standup in 10 min" + }' +``` + +### Edit a previously sent message (parent or a thread reply) + +```bash +curl -s -X POST https://api.dailybot.com/v1/send-message/ \ + -H "X-API-KEY: $DAILYBOT_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "target_channels": ["C0123"], + "bot_message_id": "$db/22aca052-...", + "message": "Started at 14:00 UTC (took 6 min)" + }' +``` + +### Request fields (most-used) + +| Field | Required | Notes | +|-------|----------|-------| +| `target_users` / `target_channels` / `target_teams` | At least one | Arrays. Channels accept either a bare string id or an object `{id, channel_type?, thread?}` | +| `message` | Either `message` or `messages` | Single message body (string). | +| `messages` | (alt) | Multi-part — array of `{message, image_url?, buttons?, ...}` | +| `image_url` | No | https URL | +| `buttons` | No | `[{label, button_type: "link"|"interactive", url?|value?}]` | +| `thread_responses` | No | `[{message}, …]` — posted in the parent's thread (≤10) | +| `platform_settings` | No | Slack-only: `bot_username`, `bot_icon_url`, `bot_icon_emoji`, `is_ephemeral` | +| `metadata` | No | Arbitrary JSON | +| `skip_users_on_time_off` | No | Boolean — skip recipients currently on time-off | +| `bot_message_id` | No | Set to **edit** that message (parent or reply id) | + +### Response shape + +```json +{ + "bot_message_id": "$db/", + "thread_responses": ["$db/", "$db/"] +} +``` + +`thread_responses` is only present when the request included them. The parent id and every reply id are reusable as `bot_message_id` in a later edit. + +--- + +## Step 5 — Error Handling + +The CLI translates these to friendly messages automatically. In `--json` mode (or via curl), match on the structured `code` field, not the prose `detail`. + +| Status | Code | Meaning | Agent behavior | +|--------|------|---------|----------------| +| `200` | | Success | Surface `bot_message_id` + any `thread_responses` ids. | +| `400` | `invalid_thread_responses` | Too many (>10), bad structure, or nested targeting | Trim to ≤10 replies, no targeting on replies, retry. | +| `400` | (other) | No/invalid targets, malformed UUID, empty channel id, invalid bot identity | Surface the `detail` verbatim and fix the input. | +| `401` / `403` | | Unauthenticated / invalid auth | Suggest `dailybot login` (or, if the developer prefers, `dailybot config key=...`). | +| `403` | `cli_send_message_target_not_allowed` | Login Bearer caller targeting outside their role scope (cross-org, channel they can't post to, team they don't belong to) | Tell the developer which target was rejected and suggest either picking an in-scope target or using an org API key for org-wide reach. | +| `404` | `team_does_not_exists_or_not_enough_permissions_granted` | Team UUID is invalid or the caller can't post to it | Re-run `dailybot team list` and confirm visibility. | +| `429` | | Rate limit on the per-token CLI throttle | Wait a bit and retry; do not retry in a tight loop. | +| `5xx` | | Server error | Warn the developer and stop; this is on Dailybot's side. | + +If the auth path is **X-API-KEY**, the role-scope error (`cli_send_message_target_not_allowed`) does not apply — the API key is org-wide. + +--- + +## Step 6 — Sample Multi-turn Dialogues + +### Dialogue A — Quick channel ping + +``` +Developer: "send a Slack message to C02MRM9NF8B saying the staging deploy is done" +Agent: + 1. Confirm: "I'll send to channel C02MRM9NF8B: 'Staging deploy done ✅'. Send? (y/n)" + 2. dailybot chat send -c C02MRM9NF8B -m "Staging deploy done ✅" + 3. Surface the bot_message_id (so the developer can ask for an edit later). +``` + +### Dialogue B — Report-style post with a thread (the canonical pattern) + +``` +Developer: "post a release report to #releases: headline 'Release v2.4 shipped', and in the thread add the changelog and the rollout time" +Agent: + 1. (Channel id needed — ask the developer for the id of #releases, e.g. C0123456789) + 2. Confirm: + "I'll post to C0123456789: + Parent: 🚀 Release v2.4 shipped + Thread 1: Changelog: ... + Thread 2: Rollout: 100% at 14:30 UTC + Send? (y/n)" + 3. dailybot chat send -c C0123456789 -m "🚀 Release v2.4 shipped" \ + --thread-message "Changelog: ..." \ + --thread-message "Rollout: 100% at 14:30 UTC" \ + --json + 4. Capture the parent id + reply ids; surface all three so the developer can edit any of them later. +``` + +### Dialogue C — DM a teammate by name + +``` +Developer: "ping Sergio Florez in chat that the prod hotfix is merged" +Agent: + 1. dailybot user list --json → find "Sergio Florez" → UUID 294bf2cc-... + 2. Confirm: "I'll DM Sergio Florez (UUID 294bf2cc-...): 'Prod hotfix merged ✅'. Send? (y/n)" + 3. dailybot chat send -u 294bf2cc-... -m "Prod hotfix merged ✅" + 4. Surface the bot_message_id. +``` + +### Dialogue D — Edit the second thread reply after the rollout + +``` +Developer: "actually update the rollout reply to say 'rolled back, see incident #42'" +Agent: + 1. Use the stored REPLY2 bot_message_id from the earlier --json capture. + 2. Confirm: "I'll edit that reply to: 'Rolled back, see incident #42'. Update? (y/n)" + 3. dailybot chat update "$REPLY2" -c C0123456789 -m "Rolled back, see incident #42" + 4. Surface success. +``` + +### Dialogue E — Team not visible to the caller (role scope) + +``` +Developer: "post a heads-up to the Security team's channel" +Agent: + 1. dailybot team list → no "Security" team visible to the caller. + 2. Stop and surface (delegated from dailybot-teams): + "I don't see a team named 'Security' on your account. You may not be a member, + or it doesn't exist. Run `dailybot team list` to confirm what you can reach. + If you need org-wide reach, set an API key with `dailybot config key=...`." +``` + +--- + +## Step 7 — Confirm + +After the command runs: + +- **Success** — briefly confirm and surface ids the developer may want for an edit: + > *"Sent to #releases. Parent id `$db/cd62…` (+ 2 thread reply ids if you ever want to edit them)."* +- **Edit success** — confirm what changed: + > *"Updated reply `$db/22ac…` in #releases."* +- **Failure** — warn briefly. For `cli_send_message_target_not_allowed`, name the rejected target and suggest an in-scope alternative. +- **Skipped** — say nothing. + +--- + +## Safety & etiquette + +- **Always confirm** the message body + targets before sending. Chat is externally visible to other humans. +- **Never** send chat messages autonomously without an explicit ask, unless the developer pre-approved a flow that explicitly chains chat sends (e.g. an on-call rotation script). +- **No secret leakage.** Treat the message body the same way `dailybot-email` treats the email body — never embed API keys, tokens, or sensitive env vars. If the developer's draft contains a credential-shaped token, surface it and ask before sending. +- **No mass DMs without consent.** A `--team` target expands to every member's DM — restate the receiver count when confirming. +- **Custom bot identity is Slack-only.** If you set `--bot-name`/`--bot-icon-*` for a Teams/Discord/Google Chat target, those flags are silently ignored — call that out so the developer isn't surprised. + +--- + +## Cross-skill contract + +- **Team resolution** is delegated to `dailybot-teams` (`../teams/SKILL.md`). Do not inline `dailybot team list` parsing here — the resolver and the scoping-aware error message live in one place. +- **User resolution** uses the canonical `dailybot user list --json` directory (same as `dailybot-kudos`). PII rules apply: emails are not shown, names + UUIDs only. +- **Chat is not a substitute for `dailybot-report`.** When the developer says "report this to my team", default to `dailybot-report` (dashboard + optional broadcast). Use `dailybot-chat` only when they specifically want a chat message delivered to a chat platform. + +--- + +## Non-Blocking Rule + +Sending chat messages must **never block the developer's primary work**. If the CLI is missing, auth fails, the network is down, the role denies the target, or the command errors: + +1. Warn the developer briefly. +2. Continue with the primary task. +3. Do not retry automatically. +4. Do not enter a diagnostic loop. + +--- + +## Additional Resources + +- [`../shared/auth.md`](../shared/auth.md) — authentication setup (login OTP, API key) +- [`../shared/http-fallback.md`](../shared/http-fallback.md) — HTTP API fallback patterns +- [`../teams/SKILL.md`](../teams/SKILL.md) — team-name resolver (called by this skill) +- [`../kudos/SKILL.md`](../kudos/SKILL.md) — user-resolution pattern (same approach as Step 2a) +- **Live API spec:** `https://api.dailybot.com/api/swagger/` +- **Full agent API skill:** `https://api.dailybot.com/skill.md` +- **CLI command reference:** [`DailybotHQ/cli` — `dailybot chat send/update`](https://github.com/DailybotHQ/cli/blob/main/docs/API_REFERENCE.md) diff --git a/.agents/skills/dailybot/checkin/SKILL.md b/.agents/skills/dailybot/checkin/SKILL.md index 2fe85e6..4cf9af6 100644 --- a/.agents/skills/dailybot/checkin/SKILL.md +++ b/.agents/skills/dailybot/checkin/SKILL.md @@ -1,7 +1,7 @@ --- name: dailybot-checkin description: List and complete pending check-ins for the developer via Dailybot. Use when the developer asks to fill in their standup, answer daily questions, or complete a pending check-in. Do not use for free-text progress reports — those go through dailybot-report. -version: "1.3.0" +version: "1.7.0" documentation_url: https://api.dailybot.com/skill.md user-invocable: true metadata: {"openclaw":{"emoji":"✅","homepage":"https://dailybot.com","requires":{"anyBins":["dailybot","curl"]},"primaryEnv":"DAILYBOT_API_KEY","install":[{"id":"cli-install-script","kind":"download","url":"https://cli.dailybot.com/install.sh","label":"Install Dailybot CLI (official script — preferred on Linux/macOS)"},{"id":"pip","kind":"pip","package":"dailybot-cli","bins":["dailybot"],"label":"Install Dailybot CLI via pip (fallback if binary fails)"}]}} diff --git a/.agents/skills/dailybot/email/SKILL.md b/.agents/skills/dailybot/email/SKILL.md index c482f22..d3dfbec 100644 --- a/.agents/skills/dailybot/email/SKILL.md +++ b/.agents/skills/dailybot/email/SKILL.md @@ -1,7 +1,7 @@ --- name: dailybot-email description: Send emails to a confirmed recipient via Dailybot on behalf of the agent. Use for notifications, summaries, follow-ups, or any communication the developer asks you to send. Always confirm recipients with the developer before sending — never guess addresses. -version: "1.3.0" +version: "1.7.0" documentation_url: https://api.dailybot.com/skill.md user-invocable: false metadata: {"openclaw":{"emoji":"📧","homepage":"https://dailybot.com","requires":{"anyBins":["dailybot","curl"]},"primaryEnv":"DAILYBOT_API_KEY","install":[{"id":"cli-install-script","kind":"download","url":"https://cli.dailybot.com/install.sh","label":"Install Dailybot CLI (official script — preferred on Linux/macOS)"},{"id":"pip","kind":"pip","package":"dailybot-cli","bins":["dailybot"],"label":"Install Dailybot CLI via pip (fallback if binary fails)"}]}} diff --git a/.agents/skills/dailybot/forms/SKILL.md b/.agents/skills/dailybot/forms/SKILL.md index 56bf0ef..d330317 100644 --- a/.agents/skills/dailybot/forms/SKILL.md +++ b/.agents/skills/dailybot/forms/SKILL.md @@ -1,7 +1,7 @@ --- name: dailybot-forms -description: List and submit form responses via Dailybot. Use when the developer wants to see available forms, fill out a survey, or submit a form response. Do not use for daily check-ins — those go through dailybot-checkin. -version: "1.3.0" +description: List, inspect, submit, update, and transition form responses via Dailybot — including forms with workflow states and audience-scoped permissions. Use when the developer wants to see available forms, fill out a survey, continue an in-progress response, move a response between states, or read prior responses. Do not use for daily check-ins — those go through dailybot-checkin. +version: "1.7.0" documentation_url: https://api.dailybot.com/skill.md user-invocable: true metadata: {"openclaw":{"emoji":"📋","homepage":"https://dailybot.com","requires":{"anyBins":["dailybot","curl"]},"primaryEnv":"DAILYBOT_API_KEY","install":[{"id":"cli-install-script","kind":"download","url":"https://cli.dailybot.com/install.sh","label":"Install Dailybot CLI (official script — preferred on Linux/macOS)"},{"id":"pip","kind":"pip","package":"dailybot-cli","bins":["dailybot"],"label":"Install Dailybot CLI via pip (fallback if binary fails)"}]}} @@ -10,20 +10,34 @@ allowed-tools: Bash, Read, Grep, Glob # Dailybot Forms -You help developers list and submit form responses through Dailybot. Forms are custom questionnaires created by team leads — feedback surveys, sprint retrospectives, pulse checks, or any structured data collection. This is distinct from daily check-ins (handled by `dailybot-checkin`) and free-text reports (handled by `dailybot-report`). +> **Requires `dailybot-cli >= 1.10.0`** ([PyPI](https://pypi.org/project/dailybot-cli/1.10.0/), released 2026-05-26). The lifecycle commands (`form get`, `form responses`, `form response get`, `form update`, `form transition`, `form delete`) and the structured `--json` 4xx error shape ship in CLI 1.10.0 — earlier versions only expose `form list` and `form submit`. If `dailybot --version` reports below 1.10.0, ask the developer to run `dailybot upgrade`. See [`../SKILL.md` § Required Dailybot CLI version](../SKILL.md#required-dailybot-cli-version) for the full rationale, install commands, and version-check tooling. + +You help developers work with the full Dailybot forms lifecycle: list, inspect, submit, update, transition between workflow states, and read prior responses. Forms are custom questionnaires created by team leads — feedback surveys, retrospectives, release checklists, approval flows, or any structured data collection. Some forms are simple "fill once and done"; others have **workflow states** (e.g. `draft → review → released`) with audience-scoped permissions on who can edit and who can transition. + +This skill is distinct from daily check-ins (handled by `dailybot-checkin`) and free-text reports (handled by `dailybot-report`). + +--- + +## Upgrade-safety contract — read this before editing forms behavior + +This SKILL.md is the **universal** forms skill. It is overwritten on every upgrade of the Dailybot skill pack (managed by `skills-lock.json`). Two rules keep customer customizations safe: + +| MUST | MUST NOT | +|------|----------| +| Read `.dailybot/profile.json` and honor `vars.custom_form_skills`. | Write anything outside `.agents/skills/dailybot/`. | +| Defer to a custom skill when the resolver finds a mapping. | Read, modify, or scan files under `.agents/skills/dailybot-custom/` or any other customer-owned namespace. | +| Warn (do not error) when a registered custom-skill path is missing on disk — fall back to the generic flow. | Send `.dailybot/profile.json` contents (especially `vars`) in any report / payload to the server. | +| Document this contract verbatim here. | Embed customer-specific logic in this universal skill — if you find yourself writing `if form.name == "Release Form":`, the right answer is a custom skill under `.agents/skills/dailybot-custom/`. | + +Customer-authored form skills live at `.agents/skills/dailybot-custom//SKILL.md`. The universal skill MUST defer to them; never copy customer logic into this file. --- ## Auth model — user-scoped commands -Form commands require a **Bearer token** (user session), not an API key. -The developer must be logged in via `dailybot login`. This scopes form -access to the logged-in human's permissions — they only see forms they -have access to. +All form commands require a **Bearer token** (user session), not an API key. The developer must be logged in via `dailybot login`. This scopes form access to the logged-in human's permissions — they only see forms (and responses) they have access to, and the server enforces every audience check on the API side. -If the developer only has an API key (`DAILYBOT_API_KEY`), guide them through -`dailybot login` first. API keys authenticate agent-scoped endpoints -(`dailybot agent ...`), not user-scoped ones. +If the developer only has an API key (`DAILYBOT_API_KEY`), guide them through `dailybot login` first. API keys authenticate agent-scoped endpoints (`dailybot agent ...`), not user-scoped ones. --- @@ -31,11 +45,12 @@ If the developer only has an API key (`DAILYBOT_API_KEY`), guide them through - The developer asks "what forms do I have?", "list my forms", "show available surveys" - The developer asks to "fill out the retro form", "submit the feedback survey", "answer the pulse check" -- When the developer needs to submit structured feedback or data through a Dailybot form +- The developer wants to **continue** an in-progress form response: "keep filling the release form", "update my draft" +- The developer wants to **move a response forward**: "mark the release as approved", "transition to released", "send for review" +- The developer wants to **read prior responses**: "show me the last release form", "what was answered last time?" +- The developer wants to **delete** a response they own -Do **not** use this skill for daily standup check-ins — route those to -`dailybot-checkin` instead. Forms are ad-hoc or periodic surveys; check-ins -are recurring daily/weekly rituals tied to follow-ups. +Do **not** use this skill for daily standup check-ins — route those to `dailybot-checkin`. Forms are ad-hoc, periodic, or workflow-driven; check-ins are recurring daily/weekly rituals tied to follow-ups. --- @@ -49,55 +64,90 @@ Read and follow the authentication steps in [`../shared/auth.md`](../shared/auth dailybot status --auth 2>&1 ``` -If the output shows a logged-in user session, proceed. If not, guide them -through `dailybot login` (see auth.md for the OTP flow). +If the output shows a logged-in user session, proceed. If not, guide them through `dailybot login` (see auth.md for the OTP flow). Form commands will not work with only an API key. + +A scripted preflight that does both at once and exits with code `3` if unauthenticated: + +```bash +dailybot status --auth >/dev/null 2>&1 || { echo "Run: dailybot login"; exit 3; } +``` If auth fails or the developer declines, skip and continue with your primary task. --- -## Step 2 — List Available Forms +## Step 2 — Lifecycle Decision Tree + +When the developer asks anything form-related, walk this tree before acting: + +``` +1. Identify the target form by name or slug (or pick from a list). +2. Run `dailybot form list --json` to find its UUID and confirm visibility. +3. Run `dailybot form get --json` to read questions, workflow_enabled, + states (if any), audience configuration, and the form's slug. +4. RESOLVER: check .dailybot/profile.json → vars.custom_form_skills. + - If a custom skill is registered for this form (by UUID or by slug), + LOAD THAT SKILL'S SKILL.md and follow its instructions INSTEAD of + continuing the generic flow. + - Otherwise, continue. +5. Decide whether to continue an existing response or start fresh: + - `dailybot form responses --latest --json` + - If a response exists and its `current_state` is NOT terminal + (or the form allows reopening), prefer the update + transition path. + - Otherwise, submit a new response. +6. After every mutating call, re-read `current_state` and `allowed_transitions` + on the response to decide the next move (update? transition? done?). +``` + +The resolver step (4) is the customer-extension hook. See **Step 7 — Custom-skill resolver** below. + +--- + +## Step 3 — List Available Forms ```bash dailybot form list --json ``` -This returns all forms visible to the logged-in user, including their -questions. - -### JSON output shape +Returns all forms visible to the logged-in user. The shape is stable and machine-readable: ```json [ { "id": "", + "slug": "team-feedback", "name": "Team Feedback", + "workflow_enabled": false, "questions": [ { "uuid": "", "question": "How was your week?", "question_type": "text_field" - }, - { - "uuid": "", - "question": "Rate your workload (1-10)", - "question_type": "numeric" } ] + }, + { + "id": "", + "slug": "code-release-form", + "name": "Code Release Form", + "workflow_enabled": true, + "questions": [ ... ] } ] ``` +> The `slug` field is stable across environments (dev / staging / prod), while `id` rotates per environment. Prefer `slug` for any persistent mapping you keep across deployments. See the resolver in Step 7. + ### Present forms to the developer When forms are found: > "You have **2 forms** available in Dailybot: > -> 1. **Team Feedback** — 3 questions -> 2. **Sprint Retrospective** — 5 questions +> 1. **Team Feedback** — 3 questions (no workflow) +> 2. **Code Release Form** — 8 questions (workflow: draft → review → released) > -> Which one would you like to fill out?" +> Which one would you like to work with?" When no forms are found: @@ -105,49 +155,284 @@ When no forms are found: --- -## Step 3 — Submit a Form Response +## Step 4 — Inspect a Form + +```bash +dailybot form get --json +``` + +Use this **before** submitting or updating. It returns the form's full configuration including workflow definition and the audience-based permission flags. Treat this output as the source of truth for "what can I do on this form?". + +### JSON shape (workflow-enabled form) + +The workflow definition (states + transitions) is nested under the `workflow` key. Audience permissions live at the top level. Both are server-defined. + +```json +{ + "id": "", + "slug": "code-release-form", + "name": "Code Release Form", + "workflow_enabled": true, + "allow_reopen_from_final_state": false, + "state_change_permission": { "audience": "...", "...": "..." }, + "edit_permission": { "audience": "...", "...": "..." }, + "view_reports_permission": { "audience": "...", "...": "..." }, + "workflow": { + "states": [ + {"key": "draft", "label": "Draft", "is_initial": true, "is_final": false}, + {"key": "review", "label": "Review", "is_initial": false, "is_final": false}, + {"key": "released", "label": "Released", "is_initial": false, "is_final": true} + ], + "transitions": [ + {"from_state": "draft", "to_state": "review", "label": "Send for review"}, + {"from_state": "review", "to_state": "released", "label": "Mark released"}, + {"from_state": "review", "to_state": "draft", "label": "Back to draft"} + ] + }, + "questions": [ ... ] +} +``` + +### Audience permissions + +The three `*_permission` fields are server-evaluated. Treat them as **opaque** in this skill — never re-implement the audience evaluation client-side. The server returns `can_change_state`, `can_edit`, and `can_view_reports` (or equivalent) on each response payload as the decided result. Trust those booleans. + +--- + +## Step 5 — Workflow-state Vocabulary + +When the form has `workflow_enabled: true`, the agent must understand five fields that appear on every response payload. Surface them when they affect what the developer can do next: + +| Field | Meaning | Agent behavior | +|-------|---------|----------------| +| `current_state` | The effective state of this response right now. | Display the label. Drive the next action from it. | +| `allowed_transitions` | `[{to_state, label}]` — the moves the **current caller** can make from `current_state`. Server-computed; honors audience. | Pick one and confirm with the developer before invoking `transition`. If the list is empty, no transitions are available to the caller. | +| `can_change_state` | Boolean — whether the caller is in the audience for state changes. | If `false`, do not offer the transition path. Tell the developer the audience excludes them. | +| `allow_reopen_from_final_state` | Form-level boolean. `false` (default) means the terminal state is sticky — once reached, the response cannot move out. | If `false` and `current_state` is a final state, do not attempt a transition. If `true`, the response can transition back to a non-final state. | +| `state_history` | Append-only list of `{from_state, to_state, actor_name, at}` entries. | Surface the latest entry (who moved it last, when) when relevant for context. | + +> Never infer state transitions from labels or names — the only valid moves are the ones in `allowed_transitions`. The server's audience checks may legitimately exclude transitions the developer *thinks* should be available. + +--- + +## Step 6 — Find In-Progress Responses + +Before submitting a new response, check whether there's an in-progress one to continue: + +```bash +dailybot form responses --latest --json +``` + +### Continue-or-start idiom + +The standard shell pattern for "continue if there's an in-progress response, otherwise create one": + +```bash +RID=$(dailybot form responses --latest --json | jq -r '.[0].id // empty') +if [ -z "$RID" ]; then + RID=$(dailybot form submit --content '{...}' --yes --json | jq -r '.id') +fi +# $RID is now the response UUID — pass it to subsequent update / transition calls. +``` + +Useful flags: + +| Flag | Description | +|------|-------------| +| `--latest` | Return only the most recent response visible to the caller. | +| `--state STATE` | Filter to responses in a specific workflow state (e.g. `--state draft`). | +| `--json` | Machine-readable output (stable shape). | + +### JSON shape (single response) + +```json +{ + "id": "", + "form_id": "", + "current_state": "review", + "allowed_transitions": [ + {"to_state": "released", "label": "Mark released"}, + {"to_state": "draft", "label": "Back to draft"} + ], + "can_change_state": true, + "state_history": [ + {"from_state": null, "to_state": "draft", "actor_name": "Sergio F.", "at": "2026-05-25T14:22:11Z"}, + {"from_state": "draft", "to_state": "review", "actor_name": "Sergio F.", "at": "2026-05-26T09:05:42Z"} + ], + "content": { + "": "Auth service v2.1", + "": "Sergio, Carolina" + } +} +``` + +### Reading a single response + +```bash +dailybot form response get --json +``` + +--- + +## Step 7 — Custom-skill Resolver (`vars.custom_form_skills`) + +If the developer's repo registers a custom skill for the form being worked with, **load and follow that custom skill instead of continuing the generic flow**. This is what keeps form-specific logic out of this universal file. + +### Where the mapping lives + +In `.dailybot/profile.json` at the repo root, under the CLI's free-form `vars` namespace: + +```json +{ + "name": "API Services", + "default_metadata": { "repo": "api-services" }, + "vars": { + "active_organization_uuid": "00e2b30f-b581-44ae-8981-4cdbd060b78d", + "custom_form_skills": { + "by_uuid": { + "65de0ec6-2353-4e17-94d7-7beaa905e92a": ".agents/skills/dailybot-custom/coderelease-form" + }, + "by_slug": { + "code-release-form": ".agents/skills/dailybot-custom/coderelease-form" + } + } + } +} +``` + +> `vars` is the CLI's official escape hatch for repo-local data the CLI carries but doesn't act on — see [DailybotHQ/cli README → Repo-level profile](https://github.com/DailybotHQ/cli#repo-level-profile-dailybotprofilejson). Nesting under `vars` keeps this convention from colliding with future top-level CLI keys. + +### Resolution algorithm + +Run this **after** `dailybot form get` (you need the slug): + +```python +def resolve_custom_form_skill(profile, form): + custom = ((profile or {}).get("vars") or {}).get("custom_form_skills") or {} + by_uuid = custom.get("by_uuid") or {} + by_slug = custom.get("by_slug") or {} + + # 1) UUID-first — exact match against the form's current UUID. + if form["id"] in by_uuid: + return by_uuid[form["id"]] + + # 2) Slug fallback — survives across dev / staging / prod where UUIDs differ. + slug = form.get("slug") + if slug and slug in by_slug: + return by_slug[slug] + + # 3) None — caller continues with the generic flow. + return None +``` + +### Behavior rules + +- Resolver runs **after** `dailybot form get` returns the form payload (slug must be available). +- If the resolver returns a path, **load `/SKILL.md`** and follow its instructions instead of continuing here. +- If no profile / no `custom_form_skills` block / no match → generic flow continues. +- If the registered path does **not** exist on disk → emit a warning to the developer and fall through to the generic flow. Do **not** hard-fail; missing custom skills must not block form work. +- Never read other paths under `.agents/skills/dailybot-custom/`. Only resolve the exact path the profile registered. + +### Why two maps + +`by_uuid` is environment-specific (the UUID rotates between dev / staging / prod). `by_slug` is portable across environments because slugs are stable. Customers running both staging and prod want the same routing in both environments; that's what the slug map gives them. Recommend both maps — UUID for exact matches, slug for cross-environment robustness. + +--- + +## Markdown Content Rules — read before composing any answer + +> [!IMPORTANT] +> The Dailybot webapp renders a **constrained Markdown subset** on form-response answers. Submitted content that uses unsupported syntax falls through as plain text — usually visually broken. Both `dailybot form submit` and `dailybot form update` send `--content` strings through this same renderer. +> +> These rules apply to every value inside the `--content` JSON map. + +### Headings — single level only + +- ✅ `# Service name` — renders as a title. +- ❌ `## Subsection`, `### Detail` — only one heading level renders. Nested headings fall through as plain text (`##` becomes the literal characters in the output). + +**If you need section structure**, use a single `#` heading with bold paragraph leads beneath it, not multiple heading levels. + +### Newlines — must be real `\n` + +- ✅ JSON `"line 1\nline 2"` → renders as two lines. +- ❌ JSON `"line 1 line 2"` → renders as one paragraph (the space is just a space). + +When building `--content` strings from a heredoc or programmatic source, ensure the encoder emits literal `\n` characters in the JSON string (a real line break in a properly-escaped JSON value). + +### Supported inline syntax + +- `**bold**` +- `*italic*` +- `` `inline code` `` +- `[link text](https://example.com)` + +### Supported block syntax + +- `- bullet` lists +- `1. numbered` lists +- Fenced code blocks (```` ```language ```` … ```` ``` ````) +- `| col | col |` tables (GFM-style) + +### Authoring rule for the LLM -### 3a. Guided mode (recommended) +When composing any answer that the agent will submit on behalf of the developer: -Retrieve the form's questions and walk the developer through each one. -Different question types need different handling: +1. Use **at most one** `#` heading per answer. +2. Insert **real `\n` newlines** between paragraphs and after each list item. +3. Stick to the inline + block elements listed above. Do not reach for `##`, `>` block quotes, footnotes, definition lists, or HTML. +4. Show the developer a preview before submitting — `--content` is also Markdown, so what you build is what they'll see. + +LLMs default to multi-level headings (`##`, `###`). That's the most common authoring mistake here. Pre-flatten the structure before composing. + +--- + +## Step 8 — Submit a New Response + +Use this when no in-progress response exists for the developer (or when the form has no workflow). + +> Every `text_field` answer is rendered as Markdown. See **Markdown Content Rules** above before composing — the most common mistake is using `##` headings, which fall through as plain text. + +### 8a. Guided mode (recommended) + +Walk through each question in order. Match the answer format to the question type: | `question_type` | How to handle | -|----------------|---------------| -| `text_field` | Free-text answer — ask the developer or draft from context | -| `numeric` | Integer value — validate it's a number | -| `boolean` | Yes/No answer | -| `choice` | Pick from the form's predefined choices list | +|-----------------|---------------| +| `text_field` | Free-text answer — ask the developer or draft from session context | +| `numeric` | Integer or decimal — validate before sending | +| `boolean` | Yes/No | +| `choice` | Pick from the form's predefined choices | -For each question, present it clearly: +For each question: -> "**Team Feedback** — Question 1 of 3: +> "**Code Release Form** — Question 1 of 8: > -> *How was your week?* (free text) +> *Service name?* (text) > > Your answer?" -### 3b. Non-interactive submission +### 8b. Non-interactive submission -If you already have the answers (from context or from the developer): +If you already have the full answer set from context: ```bash dailybot form submit \ - --content '{"":"Great week — shipped the auth module","":"7"}' \ + --content '{"":"Auth service v2.1","":"Sergio, Carolina"}' \ --yes ``` -> **Timeout**: Allow at least 30 seconds for CLI commands to complete. Do not use a shorter timeout. +> **Timeout**: Allow at least 30 seconds for CLI commands to complete. ### Confirm before submitting -Always confirm the complete set of answers before sending: +Always show the complete answer set before sending: -> "Here's what I'll submit for **Team Feedback**: +> "Here's what I'll submit for **Code Release Form**: > -> 1. *How was your week?* — "Great week — shipped the auth module" -> 2. *Rate your workload (1-10)* — "7" -> 3. *Any concerns?* — "None" +> 1. *Service name?* — "Auth service v2.1" +> 2. *Released by?* — "Sergio, Carolina" +> 3. *Migration notes?* — "None" > > **Submit?** (yes / edit / cancel)" @@ -155,24 +440,151 @@ Always confirm the complete set of answers before sending: | Flag | Short | Description | |------|-------|-------------| -| `--content` | `-c` | JSON map of `{"": ""}`. Prompts when omitted. | -| `--yes` | `-y` | Skip confirmation prompt. | -| `--json` | | Emit machine-readable JSON output. | +| `--content` | `-c` | JSON map `{"": ""}`. Prompts when omitted. | +| `--state` | `-s` | Optional initial state (workflow forms only). Defaults to the form's initial state. | +| `--yes` | `-y` | Skip confirmation. | +| `--json` | | Machine-readable JSON output. | + +After submit, **re-read `current_state` and `allowed_transitions` on the returned payload** to decide the next step. + +--- + +## Step 9 — Update an Existing Response + +Use when there's an in-progress response and the developer wants to add / change answers without changing the workflow state. + +> Updates are **strictly own-only** server-side. Org admins are NOT elevated to edit another user's response through this endpoint. If the response doesn't belong to the caller, the server returns `form_response_not_found` rather than leaking ownership. +> +> Updated answer values pass through the same Markdown renderer as new submissions — see **Markdown Content Rules** above. + +```bash +dailybot form update \ + --content '{"":"Auth service v2.1.1"}' \ + --yes +``` + +Updates merge into the existing `content`. If the server returns `form_response_change_state_forbidden` on a separate transition call, the update itself is still valid — the audience check is on the transition, not the edit (subject to the form's `edit_permission`). + +### CLI flags + +| Flag | Short | Description | +|------|-------|-------------| +| `--content` | `-c` | JSON map merged into the existing `content`. | +| `--yes` | `-y` | Skip confirmation. | +| `--json` | | Machine-readable JSON output. | + +After update, re-read `current_state` and `allowed_transitions` on the returned payload. + +--- + +## Step 10 — Transition a Response + +When the form is workflow-enabled and `allowed_transitions` is non-empty: + +```bash +dailybot form transition --yes +``` + +Confirm with the developer before transitioning: + +> "I'll transition response **#a1b2** of **Code Release Form** from `review` → `released` ("Mark released"). The action will be attributed to you in the state history. Confirm? (yes / cancel)" + +### CLI flags + +| Flag | Short | Description | +|------|-------|-------------| +| `--note` | `-n` | Optional free-text note attached to the state-history entry. | +| `--yes` | `-y` | Skip confirmation. | +| `--json` | | Machine-readable JSON output. | + +After a successful transition, surface the new `current_state` and the latest `state_history` entry. + +--- + +## Step 11 — Delete a Response + +```bash +dailybot form delete --yes +``` + +Only the **author, form owner, or org admin** can delete a response (server-enforced). Always confirm before invoking — deletion is irreversible. Use a strong confirmation prompt; the developer must type the response UUID or "yes": + +> "This will permanently delete response **#a1b2** of **Code Release Form**. This cannot be undone. +> +> Type the response UUID to confirm, or 'cancel'." + +--- + +## Step 12 — Multi-turn Lifecycle Examples + +### Example A — Non-workflow form ("Team Feedback") -### Exit codes +``` +1. dailybot form list --json → find UUID for "Team Feedback" +2. dailybot form get --json → workflow_enabled: false +3. Resolver: no entry in custom_form_skills → continue generic flow +4. Guided submission: + - Question 1: "How was your week?" → developer answer + - Question 2: "Rate workload" → "7" +5. Confirm answer set → dailybot form submit → done. +``` + +Response stored. No further lifecycle moves required. + +### Example B — Workflow form ("Code Release Form") + +``` +1. dailybot form list --json → find UUID + slug +2. dailybot form get --json → workflow_enabled: true +3. Resolver: by_slug["code-release-form"] → ".agents/skills/dailybot-custom/coderelease-form" +4. Load that custom SKILL.md and follow it → it drives the whole release flow + (the custom skill handles questions, per-state required fields, default + values, channel routing, transition cadence, etc.) +``` -| Code | Meaning | -|------|---------| -| `0` | Success | -| `3` | Not authenticated — guide through `dailybot login` | -| `4` | Permission denied (403) — the developer doesn't have access to this form | -| `5` | Quota exhausted (402) — form response limit reached for the organization | -| `6` | Rate limited (60 req/min) | -| `7` | User aborted the confirmation prompt | +If the custom skill path **does not exist**, warn the developer and continue with the generic flow (Steps 8–11) — the form is still usable, just without the customer-specific logic. --- -## Step 4 — HTTP Fallback (when CLI is unavailable) +## Step 13 — Error Handling + +Map every server `code` to a clear agent action. The error shape is `{detail, code}` across all 4xx responses. + +### `--json` structured error shape + +When any `dailybot form ...` command is invoked with `--json`, errors print as: + +```json +{ + "error": "...", + "status": 403, + "code": "form_response_change_state_forbidden", + "detail": "Caller is not in the state_change_permission audience." +} +``` + +Match on `code` (not `detail`) — `detail` is human-readable and may evolve. The CLI exits with a stable, code-aligned exit value (table below). + +### Code / HTTP / exit / action + +| Server `code` | HTTP | CLI exit | Agent action | +|---------------|------|----------|--------------| +| `form_does_not_exists` | 404 | 5 | Wrong UUID. Re-run `dailybot form list` and confirm the target. | +| `form_response_not_found` | 404 | 5 | The response doesn't exist **or** belongs to another user (update is own-only). Treat as a clean miss — no information leak. Offer to start a new response. | +| `form_response_change_state_forbidden` | 403 | 4 | Stop the transition flow. The caller is not in the form's `state_change_permission` audience — even on their own response. Suggest contacting the form owner if the move is needed. | +| `final_state_locked` | 403 | 4 | Stop. The response is in a final state and `allow_reopen_from_final_state` is `false`. Explain the policy. Offer to PATCH `allow_reopen_from_final_state=true` only if the developer is the form owner. | +| `form_response_delete_forbidden` | 403 | 4 | Stop the delete flow. Explain the author / owner / admin invariant. | +| `user_can_not_see_form_responses` | 403 | 4 | Stop. The form's `view_reports_permission` audience excludes the caller. | +| `payload_too_large` | 400 | 2 | Trim `--content`. For very long answers, split into multiple updates. | +| Any other 4xx with a `detail` | — | — | Surface the `detail` text verbatim to the developer. | +| Not authenticated | 401 | 3 | Guide through `dailybot login`. | +| Rate limited | 429 | 6 | Slow down. Do not retry in a tight loop. | + +If the server returns a body without a `code` (network error, gateway error, malformed response), warn briefly and fall back to the non-blocking rule. + +--- + +## Step 14 — HTTP Fallback (when CLI is unavailable) See [`../shared/http-fallback.md`](../shared/http-fallback.md) for base patterns. @@ -185,41 +597,86 @@ curl -s -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \ "https://api.dailybot.com/v1/forms/?include=questions" ``` -### Submit a form response +### Get a single form + +```bash +curl -s -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \ + "https://api.dailybot.com/v1/forms//" +``` + +### List responses for a form + +```bash +curl -s -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \ + "https://api.dailybot.com/v1/forms//responses/?latest=true" +``` + +### Submit a response ```bash curl -s -X POST \ -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \ -H "Content-Type: application/json" \ https://api.dailybot.com/v1/forms//responses/ \ - -d '{ - "content": { - "": "Great week — shipped the auth module", - "": "7" - } - }' + -d '{"content": {"": "Auth service v2.1"}}' +``` + +### Update a response + +```bash +curl -s -X PATCH \ + -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \ + -H "Content-Type: application/json" \ + https://api.dailybot.com/v1/forms//responses// \ + -d '{"content": {"": "Auth service v2.1.1"}}' ``` +### Transition a response + +```bash +curl -s -X POST \ + -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \ + -H "Content-Type: application/json" \ + https://api.dailybot.com/v1/forms//responses//transition/ \ + -d '{"to_state": "released"}' +``` + +### Delete a response + +```bash +curl -s -X DELETE \ + -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \ + https://api.dailybot.com/v1/forms//responses// +``` + +--- + +## Step 15 — JSON Output Stability + +Every `dailybot form ...` command supports `--json`. The shapes documented above are the **stable** machine-readable contract: agents and downstream tooling can rely on them across releases. Table output (the default without `--json`) is human-only and may evolve — never parse it. + +For the canonical CLI command + payload contract, see the `CLI_AGENT_HANDOFF.md` companion document in the planning folder. + --- -## Step 5 — Confirm +## Step 16 — Confirm -After the command runs: +After every mutating command: -- **Success** — briefly confirm. Example: *"Submitted your Team Feedback form response to Dailybot."* -- **Failure** — warn briefly. If quota exhausted, mention the limit. If permission denied, suggest checking access. +- **Success** — briefly confirm the outcome and the new state (when applicable). Example: *"Submitted your Code Release Form response. It's now in `draft`."* +- **Failure** — warn briefly. Map the `code` to a concrete next step per the table in Step 13. - **Skipped** — say nothing. --- ## Non-Blocking Rule -Form operations must **never block your primary work**. If the CLI is missing, auth fails, the network is down, or the command errors: +Form operations must **never block your primary work**. If the CLI is missing, auth fails, the network is down, or any command errors: -1. Warn the developer briefly -2. Continue with the primary task -3. Do not retry automatically -4. Do not enter a diagnostic loop +1. Warn the developer briefly. +2. Continue with the primary task. +3. Do not retry automatically. +4. Do not enter a diagnostic loop. --- @@ -227,5 +684,6 @@ Form operations must **never block your primary work**. If the CLI is missing, a - [`../shared/auth.md`](../shared/auth.md) — authentication setup - [`../shared/http-fallback.md`](../shared/http-fallback.md) — HTTP API fallback patterns +- [`_custom-template/SKILL.md`](_custom-template/SKILL.md) — starter template for authoring a custom per-form skill (copy into `.agents/skills/dailybot-custom//` in your own repo) - **Live API spec:** `https://api.dailybot.com/api/swagger/` - **Full agent API skill:** `https://api.dailybot.com/skill.md` diff --git a/.agents/skills/dailybot/forms/_custom-template/SKILL.md b/.agents/skills/dailybot/forms/_custom-template/SKILL.md new file mode 100644 index 0000000..29c76a6 --- /dev/null +++ b/.agents/skills/dailybot/forms/_custom-template/SKILL.md @@ -0,0 +1,129 @@ +--- +name: dailybot-custom-form-template +description: STARTER TEMPLATE — do not consume this file in place. Copy it to .agents/skills/dailybot-custom//SKILL.md in your own repo, then customize. This is the bootstrap skeleton for authoring a per-form custom skill that the universal dailybot-forms resolver will load from .dailybot/profile.json. +version: "1.7.0" +documentation_url: https://api.dailybot.com/skill.md +user-invocable: false +allowed-tools: Bash, Read, Grep, Glob +--- + +# Custom Form Skill — Starter Template + +> [!IMPORTANT] +> **Do not use this file in place.** It lives inside the universal Dailybot skill pack (`.agents/skills/dailybot/`) only as a reference. **Copy it** to your own repo as: +> +> ```text +> .agents/skills/dailybot-custom//SKILL.md +> ``` +> +> The universal Dailybot skill pack is **managed by `skills-lock.json`** and rewritten on every upgrade. Anything you place inside `.agents/skills/dailybot/` will be overwritten. Anything under `.agents/skills/dailybot-custom/` is **customer-owned** and the installer never touches it. That separation is the entire point — keep the line clean. + +--- + +## When the universal skill loads this custom file + +The universal `dailybot-forms` skill resolves a per-form custom skill by reading `.dailybot/profile.json` in the repo root and looking up the current form under `vars.custom_form_skills`: + +```json +{ + "vars": { + "custom_form_skills": { + "by_uuid": { + "": ".agents/skills/dailybot-custom/" + }, + "by_slug": { + "": ".agents/skills/dailybot-custom/" + } + } + } +} +``` + +When either lookup matches, the universal skill stops and loads this file. Everything below this point is your custom workflow logic — write it for the specific form this skill targets. + +--- + +## 1 — Auth + +User-scoped Bearer token (`dailybot login`). This is identical to the universal forms skill — see [`../../shared/auth.md`](../../shared/auth.md). If the developer doesn't have a session, fall back to the universal skill's auth steps; don't reinvent them here. + +--- + +## 2 — State machine reference (fill in) + +Document the workflow this form uses. Read it from `dailybot form get --json` once and pin the canonical version here so future-you doesn't have to re-derive it. + +``` +draft → review "Send for review" +review → released "Mark released" +review → draft "Back to draft" +released → (final, sticky unless allow_reopen_from_final_state=true) +``` + +Keep this in sync with the server-side workflow. The server is the source of truth for `allowed_transitions`; this section is documentation only. + +--- + +## 3 — Per-state required fields + +Some forms expect specific questions to be answered before moving forward. Document the contract per state: + +| State | Required answers before transitioning out | +|-------|-------------------------------------------| +| `draft` | service name, release notes | +| `review` | reviewer list, regression-test status | +| `released` | release URL, channel-routing target | + +The custom skill should validate these locally **before** invoking the CLI's `transition` command, so the developer sees a clear "you need to fill X first" instead of a server-side audience error. + +--- + +## 4 — Default values & autofill + +If the form has fields the agent can fill from session context, document the source mapping: + +| Form question | Source | +|---------------|--------| +| `service_name` | repo name from `.dailybot/profile.json` → `default_metadata.repo` | +| `released_by` | logged-in user from `dailybot status --auth --json` | +| `branch` | `git rev-parse --abbrev-ref HEAD` | + +Always confirm the autofilled values with the developer before submitting. + +--- + +## 5 — Channel routing reminders + +If a transition triggers a side-effect (post to Slack, page on-call, email stakeholders), document it here so the agent surfaces the side-effect during the confirmation prompt: + +> "Moving this response to `released` will notify `#releases` in Slack and email the stakeholders list. Confirm? (yes / cancel)" + +The server owns the actual notifications — this section is about what to tell the developer in the confirmation prompt. + +--- + +## 6 — Recovery flows + +What does the agent do when: + +- The latest response is in a final state but the developer says "I need to re-open" → guide them to a new response (or, if they own the form, suggest `allow_reopen_from_final_state=true`). +- The developer's audience does not include the requested transition (`form_response_change_state_forbidden`) → tell them who can do it; do not retry. +- A required field is missing → list the gaps, ask the developer to fill them, then re-attempt the transition. + +--- + +## 7 — Reference implementation + +For a complete reference of this template applied to a real workflow form, see the Dailybot-internal code-release skill at `api-services/.agents/skills/dailybot-custom/coderelease-form/SKILL.md` (ships in the `api-services` repo, separate from this skill pack). It demonstrates per-state validation, autofill from repo metadata, and channel-routing reminders end-to-end. + +--- + +## 8 — Keep customizations under `dailybot-custom/` + +| OK | Not OK | +|----|--------| +| `.agents/skills/dailybot-custom/coderelease-form/SKILL.md` | `.agents/skills/dailybot/forms/coderelease-form/SKILL.md` | +| `.agents/skills/dailybot-custom/onboarding-survey/SKILL.md` | Editing the universal `.agents/skills/dailybot/forms/SKILL.md` directly | +| Registering your skill in `.dailybot/profile.json` → `vars.custom_form_skills` | Hardcoding form UUIDs into the universal skill | + +If you find yourself wanting to edit the universal `dailybot-forms` skill to handle one specific form, stop and author a custom skill here instead. That's the contract the resolver exists to make safe. diff --git a/.agents/skills/dailybot/health/SKILL.md b/.agents/skills/dailybot/health/SKILL.md index ad923be..62b4a83 100644 --- a/.agents/skills/dailybot/health/SKILL.md +++ b/.agents/skills/dailybot/health/SKILL.md @@ -1,7 +1,7 @@ --- name: dailybot-health description: Announce agent online/offline status to Dailybot and receive pending messages from the team. Use for long-running or scheduled agents to stay visible and pick up instructions. -version: "1.3.0" +version: "1.7.0" documentation_url: https://api.dailybot.com/skill.md user-invocable: false metadata: {"openclaw":{"emoji":"💚","homepage":"https://dailybot.com","requires":{"anyBins":["dailybot","curl"]},"primaryEnv":"DAILYBOT_API_KEY","install":[{"id":"cli-install-script","kind":"download","url":"https://cli.dailybot.com/install.sh","label":"Install Dailybot CLI (official script — preferred on Linux/macOS)"},{"id":"pip","kind":"pip","package":"dailybot-cli","bins":["dailybot"],"label":"Install Dailybot CLI via pip (fallback if binary fails)"}]}} diff --git a/.agents/skills/dailybot/kudos/SKILL.md b/.agents/skills/dailybot/kudos/SKILL.md index 2fc3afe..0c8d501 100644 --- a/.agents/skills/dailybot/kudos/SKILL.md +++ b/.agents/skills/dailybot/kudos/SKILL.md @@ -1,7 +1,7 @@ --- name: dailybot-kudos -description: Give kudos to a teammate via Dailybot to recognize their contributions. Use when the developer wants to thank or recognize someone on the team. Do not use for general progress reports — those go through dailybot-report. -version: "1.3.0" +description: Give kudos to a teammate or to an entire team via Dailybot to recognize their contributions. Use when the developer wants to thank or recognize one person, or recognize a whole team (e.g. "kudos al equipo Engineering"). Do not use for general progress reports — those go through dailybot-report. +version: "1.7.0" documentation_url: https://api.dailybot.com/skill.md user-invocable: true metadata: {"openclaw":{"emoji":"🏆","homepage":"https://dailybot.com","requires":{"anyBins":["dailybot","curl"]},"primaryEnv":"DAILYBOT_API_KEY","install":[{"id":"cli-install-script","kind":"download","url":"https://cli.dailybot.com/install.sh","label":"Install Dailybot CLI (official script — preferred on Linux/macOS)"},{"id":"pip","kind":"pip","package":"dailybot-cli","bins":["dailybot"],"label":"Install Dailybot CLI via pip (fallback if binary fails)"}]}} @@ -10,32 +10,42 @@ allowed-tools: Bash, Read, Grep, Glob # Dailybot Kudos +> **Requires `dailybot-cli >= 1.10.0`** ([PyPI](https://pypi.org/project/dailybot-cli/1.10.0/), released 2026-05-26) for team-targeted kudos (`--team`). User-only kudos (`--to`) work on earlier versions, but the team-resolution path documented below assumes 1.10.0. The HTTP fallback payload also changed in 1.10.0 — see Step 7. If `dailybot --version` reports below 1.10.0, ask the developer to run `dailybot upgrade`. See [`../SKILL.md` § Required Dailybot CLI version](../SKILL.md#required-dailybot-cli-version) for install commands and version-check tooling. + You help developers recognize teammates by sending kudos through Dailybot. Kudos are team-visible appreciation messages — the whole team sees them in Dailybot's recognition feed and in connected chat platforms (Slack, Teams, Discord). +Two recipient types are supported: + +- **User kudos** — "kudos to Jane Doe" → single named recipient. +- **Team kudos** — "kudos al equipo Engineering" → every active member of the team (the caller is excluded server-side, so giving kudos to your own team doesn't bounce as self-kudos). + --- ## Auth model — user-scoped commands -Kudos commands require a **Bearer token** (user session), not an API key. -The developer must be logged in via `dailybot login`. This scopes kudos to -the logged-in human — the kudos appear as coming from them, not from an -agent. +Kudos commands require a **Bearer token** (user session), not an API key. The developer must be logged in via `dailybot login`. This scopes kudos to the logged-in human — the kudos appear as coming from them, not from an agent. -If the developer only has an API key (`DAILYBOT_API_KEY`), guide them through -`dailybot login` first. API keys authenticate agent-scoped endpoints -(`dailybot agent ...`), not user-scoped ones. +If the developer only has an API key (`DAILYBOT_API_KEY`), guide them through `dailybot login` first. API keys authenticate agent-scoped endpoints (`dailybot agent ...`), not user-scoped ones. --- ## When to Use -- The developer asks "give kudos to Jane", "recognize Alice for the PR review", "thank Bob" -- After a collaborative session where a teammate helped significantly -- When the developer explicitly wants to send team recognition +Trigger phrases the agent should recognize: -Do **not** send kudos autonomously without the developer's explicit request. -Kudos are a social action with the developer's name attached — always -confirm intent. +**User kudos:** +- "give kudos to Jane" +- "recognize Alice for the PR review" +- "thank Bob for the help" +- "felicita a Carolina por…" + +**Team kudos:** +- "kudos to the engineering team" +- "give kudos al equipo X" +- "felicita al team de QA" +- "thank the entire backend team" + +Do **not** send kudos autonomously without the developer's explicit request. Kudos are a social action with the developer's name attached — always confirm intent. --- @@ -49,18 +59,42 @@ Read and follow the authentication steps in [`../shared/auth.md`](../shared/auth dailybot status --auth 2>&1 ``` -If the output shows a logged-in user session, proceed. If not, guide them -through `dailybot login` (see auth.md for the OTP flow). +If the output shows a logged-in user session, proceed. If not, guide them through `dailybot login` (see auth.md for the OTP flow). If auth fails or the developer declines, skip and continue with your primary task. --- -## Step 2 — Resolve the Recipient +## Step 2 — Identify the Recipient Type + +The developer may refer to: + +- **A user** by full name or UUID → user-resolution path. +- **A team** by name → team-resolution path (delegated to `dailybot-teams`). +- **Both** in the same kudos (rare but supported) → use both flags. + +Decide before resolving — the routing differs. + +### Resolution flow + +``` +1. Detect target type from the developer's phrasing. + - "the X team", "el equipo X", "team de X" → TEAM + - "to Jane", "para Carolina", "thank Bob" → USER +2. For USER targets → existing user-resolution path (Step 3). +3. For TEAM targets → delegate to `dailybot-teams` (Step 4). +4. Build the CLI invocation (Step 5): + - dailybot kudos give [--to ] [--team ] --message "..." + - At least one of --to / --team must be present. +5. Confirm with the developer before sending — show the resolved names + UUIDs + AND, for team kudos, the expanded receiver count from the server. +``` + +--- + +## Step 3 — Resolve a User Recipient -The developer may refer to a teammate by name. You need either their -**full name** (the CLI resolves it against the organization directory) or -their **user UUID**. +The developer may refer to a teammate by name. You need either their **full name** (the CLI resolves it against the organization directory) or their **user UUID**. ### Look up team members (if needed) @@ -68,11 +102,9 @@ their **user UUID**. dailybot user list --json ``` -This returns all organization members with their names and UUIDs. Use this -to resolve ambiguous references or to confirm the recipient. +This returns all organization members with their names and UUIDs. Use this to resolve ambiguous references or to confirm the recipient. -**Privacy note:** Email addresses are intentionally not shown — user emails -are PII. Use the full name or UUID to identify recipients. +**Privacy note:** Email addresses are intentionally not shown — user emails are PII. Use the full name or UUID to identify recipients. ### Present the match to the developer @@ -91,11 +123,36 @@ If the name is ambiguous (matches multiple people): --- -## Step 3 — Compose and Send Kudos +## Step 4 — Resolve a Team Recipient (delegated to `dailybot-teams`) + +When the developer targets a team by name, **delegate to the `dailybot-teams` skill** rather than re-implementing the resolver. This keeps the scoping-aware error message consistent across skills. + +Concretely, the agent runs: + +```bash +dailybot team list --json +``` + +…then applies the canonical `resolve_team_by_name` from [`../teams/SKILL.md`](../teams/SKILL.md): + +- Match on `name` case-insensitively, exactly (no partial matches). +- Single match → use that team's UUID. +- Multiple matches → prompt the developer to disambiguate. +- **No match** → stop and surface the scoping-aware message from `dailybot-teams`: + + > "I don't see a team named '' on your account. You may not be a member, or it doesn't exist. Org admins see all teams in the org; members see only the teams they belong to. Run `dailybot team list` to confirm what you have access to." + +**Never inline the team list parsing here.** If the resolver logic changes in the future (workspace-scoped teams, archived-team filtering), it should change in one place. + +--- + +## Step 5 — Compose and Send Kudos ### Confirm before sending -Always confirm the kudos content with the developer before sending: +Always confirm the kudos content with the developer before sending. The confirmation differs for user vs. team kudos. + +**User kudos confirmation:** > "I'll send this kudos via Dailybot: > @@ -104,8 +161,18 @@ Always confirm the kudos content with the developer before sending: > > **Send?** (yes / edit / cancel)" +**Team kudos confirmation:** include the resolved team name and the **expected expanded receiver count** so the developer knows how many people will see it. The server excludes the caller from the expansion automatically — call that out so the developer doesn't worry about pre-filtering. + +> "I'll give kudos to the **Engineering team** (8 active members, excluding you). +> +> **Message:** *Por el release de auth — equipo enorme.* +> +> **Send?** (yes / edit / cancel)" + ### Send via CLI +**User kudos:** + ```bash dailybot kudos give \ --to "Jane Doe" \ @@ -113,45 +180,130 @@ dailybot kudos give \ --yes ``` -> **Timeout**: Allow at least 30 seconds for CLI commands to complete. Do not use a shorter timeout. +**Team kudos:** + +```bash +dailybot kudos give \ + --team \ + --message "Por el release de auth — equipo enorme." \ + --yes \ + --json +``` + +**Both at once** (rare but supported): + +```bash +dailybot kudos give \ + --to \ + --team \ + --message "Jane — and the whole Engineering team — saved the launch." \ + --yes +``` + +> **Timeout**: Allow at least 30 seconds for CLI commands to complete. ### CLI flags | Flag | Short | Description | |------|-------|-------------| -| `--to` | `-t` | Receiver full name or UUID. Required. | +| `--to` | `-t` | User receiver — full name or UUID. Optional if `--team` is provided. | +| `--team` | | Team UUID. Optional if `--to` is provided. At least one of `--to` / `--team` is required. | | `--message` | `-m` | Kudos message (team-visible). Required. | -| `--value` | | Optional company value UUID to tag the kudos. | +| `--value` | | Optional company value UUID to tag the kudos. | | `--yes` | `-y` | Skip confirmation prompt. | -| `--json` | | Emit machine-readable JSON output. | +| `--json` | | Emit machine-readable JSON output. | + +### Exit codes & error codes + +The server's `{detail, code}` 4xx shape is surfaced verbatim in `--json` mode as `{ error, status, code, detail }`. Match on `code`, not on `detail`: -### Exit codes +```json +{ + "error": "...", + "status": 400, + "code": "no_valid_team", + "detail": "Team UUID is not valid." +} +``` -| Code | Meaning | -|------|---------| -| `0` | Success | -| `2` | Ambiguous or invalid receiver — list matches and ask the developer to choose | -| `3` | Not authenticated — guide through `dailybot login` | -| `4` | Self-kudos attempted, or daily kudos limit reached | -| `6` | Rate limited (60 req/min) | +| Exit | Server `code` | Meaning | Agent behavior | +|------|---------------|---------|----------------| +| `0` | | Success | Surface the response (including expanded receiver count for team kudos). | +| `2` | `no_users_found` | Some receivers couldn't be found or were duplicates. | "Some receivers couldn't be found or were duplicates. Re-check the inputs." | +| `2` | `no_valid_users` | The receiver list ended up empty (or the legacy `receivers` field was sent). | "The receiver list ended up empty. Check `--to` and `--team` resolve correctly." | +| `2` | `no_valid_team` | The provided team didn't resolve to a valid target. | "I couldn't find that team. Check `dailybot team list` to confirm it's visible to you." | +| `3` | | Not authenticated | Guide through `dailybot login`. | +| `4` | | Self-kudos attempted, or daily kudos limit reached | If self-kudos (single user `--to`), explain it isn't allowed. If daily limit, mention it resets tomorrow. | +| `6` | | Rate limited (60 req/min) | Slow down. Do not retry in a tight loop. | +| (any 4xx) | (other) | Other server error | Surface the `detail` text verbatim. | ### Safety constraints -- **No self-kudos.** The CLI prevents giving kudos to yourself (exit code 4). - If the developer asks to send kudos to themselves, explain this isn't - allowed and suggest recognizing a teammate instead. -- **Daily limit.** Organizations may have a daily kudos limit per user. - If hit (exit code 4 with 406 status), inform the developer and move on. +- **No self-kudos to yourself directly.** If the developer asks to give kudos to themselves via `--to`, the CLI rejects it. Explain this and suggest recognizing a teammate instead. +- **Team kudos to your own team are OK.** The server's `_get_receivers_from_teams` excludes the caller from the expanded membership, so giving kudos to a team you belong to does not trip the self-kudos check. The agent doesn't need to pre-filter — the server is the source of truth. +- **Daily limit.** Organizations may have a daily kudos limit per user. If hit (exit code `4` with 406 status), inform the developer and move on. + +--- + +## Step 6 — Sample Multi-turn Dialogues + +### Dialogue A — User kudos + +``` +Developer: "give kudos to Carolina por la review" +Agent: + 1. dailybot user list --json → resolve "Carolina" → UUID + 2. Confirm: "I'll send kudos to Carolina Pérez. Message: 'Por la review'. Send? (y/n)" + 3. dailybot kudos give --to --message "Por la review" --yes --json + 4. Surface response. +``` + +### Dialogue B — Team kudos + +``` +Developer: "kudos al equipo Engineering por el release" +Agent: + 1. (Delegate to dailybot-teams) dailybot team list --json + → resolve "Engineering" → UUID (member_count: 8) + 2. Confirm: "I'll give kudos to the Engineering team + (8 active members, excluding you). + Message: 'Por el release'. Confirm? (y/n)" + 3. dailybot kudos give --team --message "Por el release" --yes --json + 4. Surface response — including the expanded receiver count. +``` + +### Dialogue C — Team not visible to caller + +``` +Developer: "give kudos to the Mobile team for the iOS launch" +Agent: + 1. (Delegate to dailybot-teams) dailybot team list --json + → no match for "Mobile" + 2. "I don't see a team named 'Mobile' on your account. You may not be a member, + or it doesn't exist. Org admins see all teams in the org; members see only + the teams they belong to. Run `dailybot team list` to confirm what you + have access to." + 3. Stop. Do not invoke kudos give with a guessed UUID. +``` --- -## Step 4 — HTTP Fallback (when CLI is unavailable) +## Step 7 — HTTP Fallback (when CLI is unavailable) See [`../shared/http-fallback.md`](../shared/http-fallback.md) for base patterns. **Important:** Kudos endpoints use **Bearer token** auth, not API key auth. -### List team members (to resolve names) +### List teams (to resolve team names) + +```bash +curl -s -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \ + https://api.dailybot.com/v1/teams/ +``` + +The list is role-scoped server-side. + +### List org members (to resolve user names) ```bash curl -s -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \ @@ -160,7 +312,9 @@ curl -s -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \ The response is paginated — follow the `next` URL until null (max 50 pages). -### Send kudos +> **Payload migration:** the `POST /v1/kudos/` body now uses `user_uuid_receivers` (for individuals) and `team_uuid_receivers` (for teams). The **legacy `receivers` field is gone** — sending it will result in `no_valid_users`. The CLI handles this transparently; HTTP fallback callers must update their payloads. + +### Send kudos to a user ```bash curl -s -X POST \ @@ -168,29 +322,63 @@ curl -s -X POST \ -H "Content-Type: application/json" \ https://api.dailybot.com/v1/kudos/ \ -d '{ - "receivers": [""], + "user_uuid_receivers": [""], "content": "Shipped the auth refactor cleanly — great work!" }' ``` +### Send kudos to a team + +```bash +curl -s -X POST \ + -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \ + -H "Content-Type: application/json" \ + https://api.dailybot.com/v1/kudos/ \ + -d '{ + "team_uuid_receivers": [""], + "content": "Por el release de auth — equipo enorme." + }' +``` + +### Send kudos to both + +```bash +curl -s -X POST \ + -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \ + -H "Content-Type: application/json" \ + https://api.dailybot.com/v1/kudos/ \ + -d '{ + "user_uuid_receivers": [""], + "team_uuid_receivers": [""], + "content": "Jane and the whole Engineering team saved the launch." + }' +``` + --- -## Step 5 — Confirm +## Step 8 — Confirm After the command runs: -- **Success** — briefly confirm. Example: *"Kudos sent to Jane Doe via Dailybot!"* -- **Failure** — warn briefly. If self-kudos, explain the restriction. If daily limit, mention it resets tomorrow. +- **Success (user kudos)** — briefly confirm. Example: *"Kudos sent to Jane Doe via Dailybot!"* +- **Success (team kudos)** — surface the resolved receiver count. Example: *"Kudos sent to the Engineering team (8 active members) via Dailybot!"* +- **Failure** — warn briefly. Map the `code` per the error table in Step 5. - **Skipped** — say nothing. --- ## Writing Good Kudos -- **Be specific** — mention what the person did, not just "great job" -- **Be genuine** — the whole team sees kudos; they should feel earned -- **Keep it concise** — one or two sentences -- **Reference the work** — "Great PR review on the auth module" > "Thanks for helping" +- **Be specific** — mention what the person/team did, not just "great job". +- **Be genuine** — the whole team sees kudos; they should feel earned. +- **Keep it concise** — one or two sentences. +- **Reference the work** — "Great PR review on the auth module" > "Thanks for helping". + +--- + +## Cross-skill contract + +The kudos skill **delegates team-name resolution to `dailybot-teams`**. Do not inline the `dailybot team list` parsing logic here — the resolver is one source of truth, in [`../teams/SKILL.md`](../teams/SKILL.md). If the resolver's behavior changes (workspace-scoped teams, archived-team filtering, etc.), the change lands there and propagates automatically. --- @@ -198,10 +386,10 @@ After the command runs: Sending kudos must **never block your primary work**. If the CLI is missing, auth fails, the network is down, or the command errors: -1. Warn the developer briefly -2. Continue with the primary task -3. Do not retry automatically -4. Do not enter a diagnostic loop +1. Warn the developer briefly. +2. Continue with the primary task. +3. Do not retry automatically. +4. Do not enter a diagnostic loop. --- @@ -209,5 +397,6 @@ Sending kudos must **never block your primary work**. If the CLI is missing, aut - [`../shared/auth.md`](../shared/auth.md) — authentication setup - [`../shared/http-fallback.md`](../shared/http-fallback.md) — HTTP API fallback patterns +- [`../teams/SKILL.md`](../teams/SKILL.md) — team-name resolver (called by this skill) - **Live API spec:** `https://api.dailybot.com/api/swagger/` - **Full agent API skill:** `https://api.dailybot.com/skill.md` diff --git a/.agents/skills/dailybot/messages/SKILL.md b/.agents/skills/dailybot/messages/SKILL.md index 85302f6..1243065 100644 --- a/.agents/skills/dailybot/messages/SKILL.md +++ b/.agents/skills/dailybot/messages/SKILL.md @@ -1,7 +1,7 @@ --- name: dailybot-messages description: Check for pending messages and instructions from your team via Dailybot. Use when starting a work session, when idle, or when asked what to work on next. Messages are instructions that should influence your work. -version: "1.3.0" +version: "1.7.0" documentation_url: https://api.dailybot.com/skill.md user-invocable: false metadata: {"openclaw":{"emoji":"📬","homepage":"https://dailybot.com","requires":{"anyBins":["dailybot","curl"]},"primaryEnv":"DAILYBOT_API_KEY","install":[{"id":"cli-install-script","kind":"download","url":"https://cli.dailybot.com/install.sh","label":"Install Dailybot CLI (official script — preferred on Linux/macOS)"},{"id":"pip","kind":"pip","package":"dailybot-cli","bins":["dailybot"],"label":"Install Dailybot CLI via pip (fallback if binary fails)"}]}} diff --git a/.agents/skills/dailybot/report/SKILL.md b/.agents/skills/dailybot/report/SKILL.md index c99cfac..1cb4016 100644 --- a/.agents/skills/dailybot/report/SKILL.md +++ b/.agents/skills/dailybot/report/SKILL.md @@ -1,7 +1,7 @@ --- name: dailybot-report description: Report work progress to Dailybot. Activate after completing a discrete task or subtask, or after any batch of edits that modifies 3 or more files. Compose a standup-style update describing what changed and why. -version: "1.3.0" +version: "1.7.0" documentation_url: https://api.dailybot.com/skill.md user-invocable: true metadata: {"openclaw":{"emoji":"📡","homepage":"https://dailybot.com","requires":{"anyBins":["dailybot","curl"]},"primaryEnv":"DAILYBOT_API_KEY","install":[{"id":"cli-install-script","kind":"download","url":"https://cli.dailybot.com/install.sh","label":"Install Dailybot CLI (official script — preferred on Linux/macOS)"},{"id":"pip","kind":"pip","package":"dailybot-cli","bins":["dailybot"],"label":"Install Dailybot CLI via pip (fallback if binary fails)"}]}} @@ -41,7 +41,21 @@ to a global agent config file (`CLAUDE.md`, `AGENTS.md`, etc.) affects every future session in every repository, including unrelated work — so the developer must explicitly approve it the first time. -### Check if the trigger is already installed +There are **two independent opt-ins**, and you should consider both every +first run: + +- **Step 0a — Prompt trigger** (works on every agent): a standing + instruction in the global config file. +- **Step 0b — Hook enforcement** (CLI >= 1.12.0, harnesses with a hook + system): deterministic, harness-driven reminders. + +Check each one separately. **Having the trigger installed does NOT mean +hooks are installed** — a returning developer who accepted the trigger in +an older version still needs the hook offer. Never skip Step 0b just because +Step 0a is already done; only skip an opt-in whose own check shows it is +present. + +### Step 0a — Check if the prompt trigger is already installed Identify which agent you are and run the corresponding check: @@ -56,9 +70,10 @@ Identify which agent you are and run the corresponding check: | Cline | `grep -q "dailybot-auto-activation" ~/.cline/.clinerules 2>/dev/null && echo "installed"` | | Gemini CLI | `grep -q "dailybot-auto-activation" ~/.gemini/GEMINI.md 2>/dev/null && echo "installed"` | -If output says "installed" — skip to Step 1. +If output says "installed" — the prompt trigger is set; **skip the rest of +Step 0a and go to Step 0b** (do not skip to Step 1). -### If missing — ask before creating +#### If missing — ask before creating Read [`triggers.md`](triggers.md) for the exact file path and content for the current agent. @@ -83,16 +98,73 @@ Otherwise, show the developer this prompt **before writing anything**: - **Yes** — write the trigger block exactly as shown, including the `dailybot-auto-activation` opening and closing markers from `triggers.md`, - then continue to Step 1. -- **No / not now** — skip auto-activation for this session and continue to - Step 1. Do not re-ask in the same session. + then continue to Step 0b. +- **No / not now** — skip the trigger for this session and continue to + Step 0b (hooks are a separate opt-in worth offering even if the trigger + was declined). Do not re-ask about the trigger in the same session. If the developer accepts, briefly confirm: > "Added. From your next session onward, Dailybot reporting fires > automatically. Remove the marked block in `` to disable." -Then proceed to Step 1. +Then continue to **Step 0b** (do not skip to Step 1 — hooks are a separate +opt-in). + +### Step 0b — Hook enforcement (recommended, CLI >= 1.12.0) + +Trigger blocks are advisory — the model can forget them in long sessions. +Since `dailybot-cli` **1.12.0**, the CLI ships a `dailybot hook` command +group that the harness itself invokes at session start, after file edits, +and at the end of every turn, making the reminders **deterministic**. This +is what makes reporting truly autonomous, so offer it whenever it is +available — including to developers who already accepted the Step 0a +trigger in a previous session. + +#### Check whether hooks apply, and whether they are already installed + +1. **CLI version.** Run `dailybot --version`. If it reports below `1.12.0` + (or the CLI is absent), the `dailybot hook` group does not exist — skip + Step 0b silently and continue to Step 1. The Step 0a trigger alone still + works. +2. **Harness support.** If the current harness has no lifecycle-hook system + (e.g. Cline today), skip Step 0b silently — Step 0a covers it. +3. **Already installed?** Check whether the hook config already references + `dailybot hook`, and skip to Step 1 if so: + + | Agent | Check | + |-------|-------| + | Claude Code | `grep -rq "dailybot hook" ~/.claude/settings.json .claude/settings.json 2>/dev/null && echo "installed"` | + | Cursor | `grep -rq "dailybot hook" ~/.cursor/hooks.json .cursor/hooks.json 2>/dev/null && echo "installed"` | + | Codex | `grep -rq "dailybot hook" ~/.codex/hooks.json .codex/hooks.json 2>/dev/null && echo "installed"` | + | Copilot | `grep -rq "dailybot hook" .github/hooks/ 2>/dev/null && echo "installed"` | + | Gemini CLI | `grep -rq "dailybot hook" ~/.gemini/settings.json .gemini/settings.json 2>/dev/null && echo "installed"` | + + If output says "installed" — hooks are already set; continue to Step 1. + +#### If missing — ask before creating + +Read [`hooks.md`](hooks.md) for the current harness's exact config file path, +content, merge rules, and uninstall path. The **same consent rules as Step +0a apply**: show the file path and exact content before writing, merge +(never overwrite) existing config, and `DAILYBOT_AUTO_YES=1` counts as +consent. A repo-level config (`.claude/settings.json`, `.cursor/hooks.json`, +…) committed to the repository gives the whole team autonomous reporting on +clone — offer that when the developer is in a shared project. + +If the developer declines, continue to Step 1 and do not re-ask in the same +session. The Step 0a trigger still provides (probabilistic) coverage. + +### Responding to injected Dailybot reminders + +When a hook injects a reminder ("commits have landed since the last +report…" / "sustained work without a progress report…") into your context: + +- **Meaningful unit complete** (including non-commit work — research, + analysis, documents) → compose and send the report now (Steps 3–7). +- **Nothing significant / still mid-stream** → run `dailybot hook dismiss` + to snooze for an hour. Either report or dismiss — never ignore the + reminder silently. --- @@ -271,6 +343,24 @@ curl -s -X POST https://api.dailybot.com/v1/agent-reports/ \ }' ``` +### Response + +A successful request returns `201` with the created report, including a +`url` field that points to where the report landed in Dailybot: + +```json +{ + "id": "", + "url": "https://app.dailybot.com/agents/report/", + "...": "..." +} +``` + +Capture that `url` and surface it when you confirm (see Step 7). The CLI +prints the same link automatically as a `View:` line **from `dailybot-cli` +1.11.0 onward**; on earlier CLIs the printed output omits it, but the HTTP +`201` body above always carries the `url` — read it from there. + --- ## Step 5 — Trigger Check @@ -362,7 +452,7 @@ For side-by-side examples, see [`examples.md`](examples.md). After the command runs: -- **Success** — briefly confirm what was reported. Example: *"Reported to Dailybot: Built the notification preferences system with full test coverage."* +- **Success** — briefly confirm what was reported, and include the placement link the response returns (the `url` field, printed by the CLI as `View:` from `dailybot-cli` 1.11.0 onward, and always present in the HTTP `201` body) so the developer can jump straight to where it landed. Example: *"Reported to Dailybot: Built the notification preferences system with full test coverage — view it at https://app.dailybot.com/agents/report/."* If no `url` is surfaced (an older backend, or a CLI below 1.11.0 where you only see the printed output), just confirm the report without a link. - **Failure** — warn briefly. Do not retry in a loop. Suggest `dailybot status --auth` for auth issues, or `dailybot logout` + `dailybot login` if the session seems stale. - **Skipped** — say nothing. Complete silence is the correct response. @@ -382,6 +472,7 @@ Reporting must **never block your primary work**. If the CLI is missing, auth fa ## Additional Resources - [`triggers.md`](triggers.md) — auto-activation trigger templates for each supported agent +- [`hooks.md`](hooks.md) — deterministic hook enforcement (CLI >= 1.12.0): per-harness configs, reminder handling, `dismiss` - [`significance.md`](significance.md) — when to report and when to stay silent, with edge cases - [`writing-guide.md`](writing-guide.md) — writing templates by work type, action verbs, rate limiting - [`examples.md`](examples.md) — 15 side-by-side good vs bad comparisons diff --git a/.agents/skills/dailybot/report/hooks.md b/.agents/skills/dailybot/report/hooks.md new file mode 100644 index 0000000..e881ec1 --- /dev/null +++ b/.agents/skills/dailybot/report/hooks.md @@ -0,0 +1,154 @@ +# Hook Enforcement — Deterministic Report Reminders + +Prompt instructions (the [`triggers.md`](triggers.md) blocks) are +**probabilistic** — in long sessions the model can forget them. Lifecycle +hooks are **deterministic**: the agent harness itself runs a Dailybot CLI +command at session start, after tool use, and at the end of every turn, and +that command decides — from local state only — whether the model should be +reminded to send a progress report. + +With hooks installed, reporting becomes fully autonomous: the developer logs +in once, and from then on the harness re-arms the reminders in every future +session, container, and repo. No human reminders, no reliance on the model's +memory. + +> **Requires `dailybot-cli >= 1.12.0`** (the `dailybot hook` command group +> first ships in 1.12.0 — [release notes](https://github.com/DailybotHQ/cli/releases/tag/v1.12.0)). +> Check with `dailybot --version`; if older, ask the developer to run +> `dailybot upgrade` once. Hooks installed against an older CLI fail +> gracefully (the harness ignores a missing command), but install-time is +> the right moment to get the version right. + +## How it works + +| Hook event (harness) | CLI command | Effect | +|----------------------|-------------|--------| +| Session start | `dailybot hook session-start --format ` | Injects context: login nudge (max once / 24 h) + unreported work left over from earlier sessions | +| After file-writing tools | `dailybot hook activity` | Records a soft work signal — catches research, analysis, and documents that never get committed | +| After a `git commit` | `dailybot hook post-commit` | Records a strong work signal | +| End of turn / stop | `dailybot hook stop --format ` | The decision point: emits a report reminder when unreported work exists, otherwise stays silent | + +All commands are local-only (git + a per-repo ledger in +`~/.config/dailybot/ledger/`), never call the network, and always exit `0` — +a failure can never break the developer's session. Anti-noise gates +(30-minute minimum interval, 15-minute cooldown, snooze, per-repo opt-out) +are built into the CLI. Full reference: +[CLI docs — AGENT_HOOKS.md](https://github.com/DailybotHQ/cli/blob/main/docs/AGENT_HOOKS.md). + +## Responding to a reminder (every agent, every session) + +When a Dailybot reminder is injected into your context by one of these +hooks: + +1. **If a meaningful unit of work is complete** — including non-commit work + such as research, analysis, or written documents — send a report now via + the [`dailybot-report` skill](SKILL.md). The successful + `dailybot agent update` resets the ledger and the reminders stop. +2. **If nothing significant happened** (or the work is still mid-stream and + you expect to keep going) — run `dailybot hook dismiss` to snooze + reminders for an hour. Never ignore the reminder silently; either report + or dismiss so the ledger reflects your judgment. +3. **Never block the developer's primary work** on either path. + +## Installation (consent required — same rules as triggers) + +Hook configs are written to the developer's harness config files. Exactly +like the auto-activation triggers in [`triggers.md`](triggers.md), this is +**opt-in**: show the file path and the exact content, explain the uninstall +path, and write only after the developer confirms. `DAILYBOT_AUTO_YES=1` +counts as consent. Merge — never overwrite — existing config files, and show +the merged result before saving. + +There is no HTML-comment marker inside JSON configs; the uninstall marker is +the command string itself — every entry contains `dailybot hook`, so +removing all hook entries whose command starts with `dailybot hook` (or +deleting the dedicated file) fully uninstalls. + +### Claude Code + +**Path:** `~/.claude/settings.json` (user-wide) or `/.claude/settings.json` +(commit it so the whole team gets autonomous reporting). + +Merge this into the existing JSON (create the file if missing): + +```json +{ + "hooks": { + "SessionStart": [ + {"hooks": [{"type": "command", "command": "dailybot hook session-start --format claude"}]} + ], + "PostToolUse": [ + {"matcher": "Write|Edit|NotebookEdit", + "hooks": [{"type": "command", "command": "dailybot hook activity"}]} + ], + "Stop": [ + {"hooks": [{"type": "command", "command": "dailybot hook stop --format claude"}]} + ] + } +} +``` + +**Verify:** `grep -q "dailybot hook" ~/.claude/settings.json` (or the repo +file). **Uninstall:** remove the three entries. + +### Cursor + +**Path:** `~/.cursor/hooks.json` (user-wide) or `/.cursor/hooks.json`. + +```json +{ + "version": 1, + "hooks": { + "sessionStart": [{"command": "dailybot hook session-start --format cursor"}], + "afterFileEdit": [{"command": "dailybot hook activity"}], + "stop": [{"command": "dailybot hook stop --format cursor"}] + } +} +``` + +The `stop` output uses Cursor's `followup_message`, which auto-submits the +reminder as the next prompt. **Uninstall:** remove the entries or delete the +file. + +### Other harnesses (Codex, Copilot, Gemini CLI, OpenCode, Windsurf) + +The CLI side is identical — only the wrapper syntax differs. Use +`--format generic` (plain text on stdout) unless the harness documents a +context-injection JSON shape, and consult the harness's own hooks reference +for the exact config schema **at install time** (schemas evolve; do not +guess): + +| Harness | Config location | End-of-turn event | Docs | +|---------|-----------------|-------------------|------| +| OpenAI Codex | `~/.codex/hooks.json` (user-level avoids the repo-trust prompt) | `Stop` | [developers.openai.com/codex/hooks](https://developers.openai.com/codex/hooks) | +| GitHub Copilot | `.github/hooks/dailybot.json` (repo) | `agentStop` | [docs.github.com — hooks reference](https://docs.github.com/en/copilot/reference/hooks-configuration) | +| Gemini CLI | `.gemini/settings.json` or `~/.gemini/settings.json` | `AfterAgent` | [geminicli.com/docs/hooks](https://geminicli.com/docs/hooks/) | +| OpenCode | plugin in `~/.config/opencode/plugins/` | `session.idle` | [opencode.ai/docs/plugins](https://opencode.ai/docs/plugins/) | +| Windsurf | `.windsurf/hooks.json` | `post_cascade_response` (cannot inject context — run-only) | [docs.devin.ai — hooks](https://docs.devin.ai/desktop/cascade/hooks) | + +Cline has no end-of-turn hook as of this writing — rely on the +[`triggers.md`](triggers.md) prompt block there. + +### Team rollout (zero per-developer setup) + +Commit the repo-level config (`.claude/settings.json`, +`.cursor/hooks.json`, `.github/hooks/dailybot.json`, …) to the repository. +Every contributor — and every fresh container — gets the hooks on clone; +the only remaining per-person step is `dailybot login`, and the +`session-start` hook itself asks for that when missing. + +## Per-repo controls + +- `.dailybot/disabled` — silences hooks (and all skill telemetry) for a repo. +- `.dailybot/profile.json` → `"report": {"min_interval_minutes": 30, "nudge": true}` + — committed team policy; `"nudge": false` turns reminders off for the repo + while keeping manual reporting available. + +## Troubleshooting + +| Symptom | Check | +|---------|-------| +| Reminders never fire | Run `dailybot hook stop` manually after a commit — any output? Then check `dailybot --version` (>= 1.12.0), `.dailybot/disabled`, and the harness config actually contains the `dailybot hook` entries | +| Reminder fires but mentions old history | Delete the repo's file under `~/.config/dailybot/ledger/` — the baseline re-anchors silently | +| Too noisy | Raise `min_interval_minutes` in `.dailybot/profile.json`, or use `dailybot hook dismiss --minutes ` | +| Harness errors on hook output | Wrong `--format` — `claude`/`cursor` emit JSON, `generic` is plain text | diff --git a/.agents/skills/dailybot/report/triggers.md b/.agents/skills/dailybot/report/triggers.md index 6c96a11..a53030f 100644 --- a/.agents/skills/dailybot/report/triggers.md +++ b/.agents/skills/dailybot/report/triggers.md @@ -6,6 +6,13 @@ Dailybot skills after completing tasks or making broad edits — primarily the `dailybot-report` skill, but also to check messages at session start and send periodic health checks. +> **Prefer hooks where available.** Trigger blocks are prompt instructions — +> advisory, and forgettable in long sessions. Since `dailybot-cli` 1.12.0 +> the harness can enforce reporting deterministically via lifecycle hooks; +> see [`hooks.md`](hooks.md). Install both when possible: the trigger block +> teaches the behavior, the hooks guarantee it. On harnesses without hook +> support (e.g. Cline), the trigger block is the only mechanism. + Step 0 in [SKILL.md](SKILL.md) uses these templates **only after the developer explicitly confirms** the skill should write to a global agent config file. Each template is wrapped in a marker so the block can be located and removed diff --git a/.agents/skills/dailybot/shared/http-fallback.md b/.agents/skills/dailybot/shared/http-fallback.md index bf5bf6e..def65e5 100644 --- a/.agents/skills/dailybot/shared/http-fallback.md +++ b/.agents/skills/dailybot/shared/http-fallback.md @@ -22,6 +22,7 @@ export DAILYBOT_API_KEY="" | `GET` | `/v1/agent-health/?agent_name=` | Retrieve last health status | | `GET` | `/v1/agent-messages/?agent_name=&delivered=false` | Poll for undelivered messages | | `POST` | `/v1/agent-email/send/` | Send an email on behalf of your agent | +| `POST` | `/v1/send-message/` | Send / edit a bot chat message (DM, channel, team). Accepts `X-API-KEY` **or** `Authorization: Bearer`. Targets `target_users` / `target_channels` / `target_teams`; optional `thread_responses[]` (≤10) posts replies in the parent's thread in the same call; passing `bot_message_id` edits that message (parent or reply). | --- diff --git a/.agents/skills/dailybot/teams/SKILL.md b/.agents/skills/dailybot/teams/SKILL.md new file mode 100644 index 0000000..6b9ed6e --- /dev/null +++ b/.agents/skills/dailybot/teams/SKILL.md @@ -0,0 +1,231 @@ +--- +name: dailybot-teams +description: Read and resolve teams visible to the authenticated user. Use when the developer references a team by name (for kudos targeting, member lookup, or routing context) and an agent needs to obtain its UUID. Other Dailybot skills (kudos, messages) delegate team-name resolution to this skill rather than duplicating the logic. +version: "1.7.0" +documentation_url: https://api.dailybot.com/skill.md +user-invocable: true +metadata: {"openclaw":{"emoji":"👥","homepage":"https://dailybot.com","requires":{"anyBins":["dailybot","curl"]},"primaryEnv":"DAILYBOT_API_KEY","install":[{"id":"cli-install-script","kind":"download","url":"https://cli.dailybot.com/install.sh","label":"Install Dailybot CLI (official script — preferred on Linux/macOS)"},{"id":"pip","kind":"pip","package":"dailybot-cli","bins":["dailybot"],"label":"Install Dailybot CLI via pip (fallback if binary fails)"}]}} +allowed-tools: Bash, Read, Grep, Glob +--- + +# Dailybot Teams + +> **Requires `dailybot-cli >= 1.10.0`** ([PyPI](https://pypi.org/project/dailybot-cli/1.10.0/), released 2026-05-26). `dailybot team list` and `dailybot team get` ship in CLI 1.10.0 — earlier versions don't expose the team commands at all. If `dailybot --version` reports below 1.10.0, ask the developer to run `dailybot upgrade`. See [`../SKILL.md` § Required Dailybot CLI version](../SKILL.md#required-dailybot-cli-version) for install commands and version-check tooling. + +You help agents resolve and read teams visible to the logged-in user. Teams are how Dailybot groups people inside an organization — they're the targets for team-scoped kudos, the routing context for some messages, and the source of truth for "who's in X?". + +This skill is primarily a **resolver dependency** for other Dailybot skills (most notably `dailybot-kudos`, which uses it to turn "kudos al equipo Engineering" into a team UUID). It also handles direct developer asks like "list my teams" or "who's in QA?". + +--- + +## Auth model — user-scoped commands + +Team-read commands require a **Bearer token** (user session), not an API key. The developer must be logged in via `dailybot login`. This scopes results to the logged-in human's permissions — they only see teams the server allows them to see. + +If the developer only has an API key (`DAILYBOT_API_KEY`), guide them through `dailybot login` first. API keys authenticate agent-scoped endpoints (`dailybot agent ...`), not user-scoped ones. + +--- + +## Security & scoping — read this before listing teams + +The server applies **role-based scoping** to every team-related read: + +- **Org admins** see all teams in their organization. +- **Members and guests** see only the teams they belong to (`teammembership_set`). + +This scoping is enforced server-side by `IsTeamMemberOrAdmin` + `PublicTeamsAPIView.get_queryset`. The skill MUST NOT attempt to widen visibility client-side. Trust the server's response verbatim. + +If the developer asks about a team the agent does not see in the role-scoped list, the correct response is: + +> "I don't see a team named '' on your account. You may not be a member, or it doesn't exist. Org admins see all teams in the org; members see only the teams they belong to. Run `dailybot team list` to confirm what you have access to." + +Never imply the team doesn't exist — only that it isn't visible to this caller. + +--- + +## When to Use + +- Another Dailybot skill asks "what's the UUID of the team named X?" (resolver delegation). +- The developer asks "what teams am I in?", "list my teams", "show org teams". +- The developer asks "who's in the Engineering team?", "members of QA". +- Before any `dailybot kudos give --team ...` invocation, to resolve the team name → UUID. + +Do **not** use this skill to enumerate org members when the goal is to recognize a single person — route that through `dailybot-kudos` (which uses the user directory). Use teams for *team-scoped* operations. + +--- + +## Step 1 — Verify Setup + +Read and follow the authentication steps in [`../shared/auth.md`](../shared/auth.md). That file covers CLI installation, login, API key setup, and agent profile configuration. + +**Additionally**, verify the developer has a user session (Bearer token): + +```bash +dailybot status --auth 2>&1 +``` + +If the output shows a logged-in user session, proceed. If not, guide them through `dailybot login` (see auth.md for the OTP flow). Team commands will not work with only an API key. + +If auth fails or the developer declines, skip and continue with your primary task. + +--- + +## Step 2 — List Teams + +```bash +dailybot team list --json +``` + +Returns the **role-scoped** list of teams visible to the caller. Trust the response verbatim — do not attempt to widen the result. + +### JSON output shape + +```json +[ + { + "uuid": "", + "name": "Engineering", + "member_count": 12 + }, + { + "uuid": "", + "name": "QA", + "member_count": 4 + } +] +``` + +If the list is empty: + +> "You don't have any teams visible. As a member, you only see teams you belong to. If you expected a team here, ask an org admin to add you." + +--- + +## Step 3 — Resolve a Team by Name → UUID (canonical resolver) + +This is the resolver other skills call into. Implement it once, here, and surface scoping-aware error messages consistently: + +```python +def resolve_team_by_name(name): + teams = cli_call("dailybot team list --json") # role-scoped server-side + matches = [t for t in teams if t["name"].lower() == name.lower()] + if not matches: + return None # caller surfaces the scoping message (see "Security & scoping" above) + if len(matches) > 1: + return prompt_user_to_disambiguate(matches) + return matches[0]["uuid"] +``` + +### Behavior rules + +- Match on `name` **case-insensitively** but exactly (no partial matches). "engineering" matches "Engineering"; "eng" does not. +- **Never guess a UUID.** If the name doesn't resolve uniquely, prompt the developer to pick from the disambiguation list. +- **Never call into the server with a guessed UUID.** If the resolver returns `None`, the calling skill stops and surfaces the scoping message. +- When using `dailybot team get ` directly, the CLI exits with code `2` on an ambiguous name match — interpret that as "prompt the developer to disambiguate", not as a generic error. +- If multiple teams have the same name (rare — same org allows duplicates only across spaces), present them to the developer: + + > "I found 2 teams named 'QA': + > + > 1. QA — 4 members + > 2. QA (Mobile) — 3 members + > + > Which one?" + +--- + +## Step 4 — Inspect a Team + +```bash +dailybot team get --with-members --json +``` + +Returns the team plus its membership when `--with-members` is set. Useful when the agent needs context like "who's in QA before I send them a message?". + +### JSON output shape (with members) + +```json +{ + "uuid": "", + "name": "Engineering", + "member_count": 12, + "members": [ + {"uuid": "", "full_name": "Carolina Pérez"}, + {"uuid": "", "full_name": "Sergio Florez"} + ] +} +``` + +**Privacy note:** Email addresses are intentionally not returned — user emails are PII. Use the full name or UUID to identify members. + +### When to surface members vs. counts + +| Developer ask | What to show | +|---------------|--------------| +| "How big is the Engineering team?" | Just `member_count`. | +| "Who's in the Engineering team?" | The `members` list (names only). | +| "Is Alice in QA?" | The `members` list, then answer based on it. | + +--- + +## Step 5 — Cross-skill Resolver Convention + +When another Dailybot skill (notably `dailybot-kudos`) needs a team UUID from a name, it MUST go through this skill — not duplicate the `dailybot team list` parsing. + +Document the contract: + +> Any other skill that needs to resolve a team name calls into `dailybot-teams` rather than re-implementing the resolver. Centralizing it keeps the scoping-aware error message consistent across skills, and ensures that future changes to how visibility is enforced (e.g. workspace-scoped teams, archived-team filtering) propagate everywhere automatically. + +Concretely: a calling skill should invoke the same `dailybot team list --json` command this skill uses, and apply the same matching algorithm. The calling skill should NOT cache the team list across invocations — visibility may change between sessions. + +--- + +## Step 6 — HTTP Fallback (when CLI is unavailable) + +See [`../shared/http-fallback.md`](../shared/http-fallback.md) for base patterns. + +**Important:** Team endpoints use **Bearer token** auth, not API key auth. + +### List teams (role-scoped) + +```bash +curl -s -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \ + https://api.dailybot.com/v1/teams/ +``` + +### Get a single team (with members) + +```bash +curl -s -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \ + "https://api.dailybot.com/v1/teams//?include=members" +``` + +The server applies the same role-based scoping as the CLI — no client-side widening. + +--- + +## Step 7 — Confirm + +- **Success** — surface the resolved team or the requested information directly. +- **Failure** — warn briefly. If the team is not in the role-scoped list, use the scoping message from the "Security & scoping" section. +- **Skipped** — say nothing. + +--- + +## Non-Blocking Rule + +Team operations must **never block your primary work**. If the CLI is missing, auth fails, the network is down, or any command errors: + +1. Warn the developer briefly. +2. Continue with the primary task (or, if invoked as a resolver, return `None` to the calling skill). +3. Do not retry automatically. +4. Do not enter a diagnostic loop. + +--- + +## Additional Resources + +- [`../shared/auth.md`](../shared/auth.md) — authentication setup +- [`../shared/http-fallback.md`](../shared/http-fallback.md) — HTTP API fallback patterns +- [`../kudos/SKILL.md`](../kudos/SKILL.md) — primary consumer of this skill's resolver +- **Live API spec:** `https://api.dailybot.com/api/swagger/` +- **Full agent API skill:** `https://api.dailybot.com/skill.md` diff --git a/AGENTS.md b/AGENTS.md index 02f5f17..dbd76ea 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -436,7 +436,7 @@ dailybot agent update --name "Claude Code" --milestone \ --metadata '{"model":"claude-opus-4-7","plan":"PLAN_agent_profiles","repo":"cli"}' ``` -Full philosophy, what to report, and what to skip: [.agents/skills/dailybot-progress-report/SKILL.md](.agents/skills/dailybot-progress-report/SKILL.md). Key rules: +Full philosophy, what to report, and what to skip: [.agents/skills/dailybot/report/SKILL.md](.agents/skills/dailybot/report/SKILL.md) (part of the vendored Dailybot agent skill pack at `.agents/skills/dailybot/`, v1.7.0, which also ships the new `chat`, `kudos`, `teams`, `forms`, `checkin` sub-skills). Key rules: - 1–3 sentences, **always in English** - Focus on WHAT + WHY, never "Agent completed…" @@ -467,7 +467,7 @@ When applying bot feedback on a PR, agents **must** skip `isMinimized == true` c Reusable **Skills** (slash commands) and **Agents** (specialized personas) live under [`.agents/`](.agents/) — the vendor-neutral standard adopted by most coding agents (Claude Code, Cursor, Codex, Gemini, Copilot, …): -- [`.agents/skills/`](.agents/skills/) — slash commands (e.g., `/quick-fix`, `/release-prep`, `/cli-command-add`, `/dailybot-progress-report`) +- [`.agents/skills/`](.agents/skills/) — slash commands (e.g., `/quick-fix`, `/release-prep`, `/cli-command-add`, plus the vendored Dailybot pack at `.agents/skills/dailybot/` with `/dailybot-report`, `/dailybot-chat`, `/dailybot-kudos`, `/dailybot-teams`, `/dailybot-forms`, `/dailybot-checkin`, `/dailybot-email`, `/dailybot-health`, `/dailybot-messages`) - [`.agents/agents/`](.agents/agents/) — agent personas (e.g., `cli-developer`, `release-manager`, `docs-writer`, `test-engineer`) - [`.agents/docs/skills_agents_catalog.md`](.agents/docs/skills_agents_catalog.md) — full index