
Dailybot
- 135 installs
- 2 repo stars
- Updated July 24, 2026
- dailybothq/agent-skill
Connect AI coding agents to their team via Dailybot's API to report progress, poll messages, run check-ins, give kudos, and send Slack/Teams/Discord chat.
About
Official Dailybot agent skill pack that connects AI coding agents to their human team through Dailybot's first-party API, routing between progress reports, message polling, email, chat, check-ins, kudos, teams, and forms. A developer uses it when they want an agent to keep their team coordinated across humans and agents.
- Nine coordinated capabilities with smart intent-based routing
- Send/edit chat and report threads on Slack, Teams, Discord, Google Chat
Dailybot by the numbers
- 135 all-time installs (skills.sh)
- Ranked #686 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/dailybothq/agent-skill --skill dailybotAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 135 |
|---|---|
| repo stars | ★ 2 |
| Last updated | July 24, 2026 |
| Repository | dailybothq/agent-skill ↗ |
What it does
Connect AI coding agents to their team via Dailybot's API to report progress, poll messages, run check-ins, give kudos, and send Slack/Teams/Discord chat.
Files
Dailybot Chat
Requires `dailybot-cli >= 1.13.1` (PyPI, latest release 2026-06-12). Thedailybot chat send/chat updatecommand group, the--thread-messageflag (≤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) first shipped in 1.13.0 (release notes); 1.13.1 is the current published version and is whatpip install --upgrade dailybot-cliwill install today. Below 1.13.0, thedailybot chatgroup does not exist — ask the developer to rundailybot upgrade. See `../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=...orDAILYBOT_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` 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`. It covers CLI installation, login (email OTP), API key setup, and agent profile configuration.
Then verify the CLI sees a usable session:
dailybot status --auth 2>&1If 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:
dailybot user list --jsonThis 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` 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
command -v dailybot- CLI found → Step 4A
- CLI not found → Step 4B (HTTP fallback; see `../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
dailybot chat send -c C0123 -m "Deploy v2.4 started 🚀"DM one or several people (by UUID, resolved in Step 2a)
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)
dailybot chat send -t <team-uuid> -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.
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-messageis 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)
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)
dailybot chat send -u ana@co.com -m "Heads up: build broke" --ephemeralEphemeral needs a --user target. A channel-only ephemeral send is skipped by the platform — the CLI warns up front.
Buttons
# 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
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": "<parent>", "thread_responses": ["<reply1>", …] }) 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:
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:
# 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` 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)
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:
{
"bot_message_id": "$db/cd626a24-...",
"thread_responses": [
"$db/22aca052-...",
"$db/1f57b5fc-..."
]
}DM a user (Bearer path — login session)
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)
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" |
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
{
"bot_message_id": "$db/<parent-id>",
"thread_responses": ["$db/<reply1>", "$db/<reply2>"]
}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-emailtreats 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
--teamtarget 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 inlinedailybot team listparsing here — the resolver and the scoping-aware error message live in one place. - User resolution uses the canonical
dailybot user list --jsondirectory (same asdailybot-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). Usedailybot-chatonly 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` — authentication setup (login OTP, API key)
- `../shared/http-fallback.md` — HTTP API fallback patterns
- `../teams/SKILL.md` — team-name resolver (called by this skill)
- `../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`
Report Examples
Side-by-side comparisons of weak and strong reports. Use these as a calibration reference.
About `--name` and `--metadata` in the rich examples below: every example assumes the repo does not ship a.dailybot/profile.json— i.e. there is no pinned identity, so each call must pass--nameexplicitly and putrepo/agent_tool/agent_nameinline in--metadata. If the repo does ship a `.dailybot/profile.json`, omit every flag the profile already sets (see `SKILL.md` § Step 4A "Pre-flight" and `../shared/repo-profile.md` for the full procedure). Don't ever copy these example flag lists wholesale into a repo with a pinned profile — it silently overrides the developer's pin.
---
Plain Reports
1. Feature implementation
Weak: "3 files modified in app/followups/ — updated serializers and tasks"
Strong: "Refactored followup notifications — managers now receive their full platform profile (avatar, contact info) instead of just a name string, improving how manager data appears in reminders."
Why: Describes the change AND its user-facing impact. No file paths.
---
2. Bug fix
Weak: "fix: handle null timezone in user profile"
Strong: "Fixed a bug where users without a timezone set would see errors on their profile page."
Why: Describes the problem users experienced, not the code change.
---
3. Frontend change
Weak: "feat: add copy icon and click feedback to hero CLI pill — pushed to dev"
Strong: "Added copy-to-clipboard functionality to the homepage CLI demo with visual feedback when users click."
Why: No branch names. Describes what the user experiences.
---
4. Multiple commits
Weak: "2 commits — latest: fix: handle null timezone in user profile"
Strong: "Fixed a bug where users without a timezone set would see errors on their profile page."
Why: One sentence about the outcome. Commit count is irrelevant to the team.
---
5. Documentation
Weak: "1 file modified: docs/technical/ARCHITECTURE_OVERVIEW.md"
Strong: "Updated the architecture documentation to reflect the new notification service integration."
Why: Describes what changed and why, not which file was edited.
---
6. Testing
Weak: "Completed testing work"
Strong: "Added test coverage for the manager profile serializer — 15 cases covering edge cases and platform variations."
Why: Specific about what was tested and the scope of coverage.
---
7. Refactoring
Weak: "refactor: clean up auth middleware"
Strong: "Refactored the authentication middleware to centralize token validation — eliminates duplicated checks across 4 endpoints."
Why: Explains the purpose and impact of the refactor.
---
8. Dependency update
Weak: "3 commits — latest: chore: update dependencies"
Strong: "Updated project dependencies to latest stable versions, including security patches for the HTTP client."
Why: Mentions the reason the update matters.
---
9. Performance fix
Weak: "perf: optimize dashboard query"
Strong: "Optimized the dashboard loading query — page now loads in under 500ms instead of 3 seconds for large teams."
Why: Quantifies the improvement.
---
10. CI/CD configuration
Weak: "ci: add e2e test step to pipeline"
Strong: "Configured the CI pipeline for automated browser tests — PRs now get E2E test results before merge."
Why: Explains what the team gets out of it.
---
Rich Reports (with structured data)
11. Major feature (milestone)
Weak:
dailybot agent update "Completed development work and all tests pass" \
--name "cursor"Strong:
dailybot agent update \
"Built the notification preferences system — users can now configure which alerts they receive and through which channels (email, in-app, Slack)." \
--name "cursor" \
--milestone \
--json-data '{"completed":["Preferences data model","REST API endpoints (CRUD)","Email channel integration","Slack channel integration","User settings UI","Test suite (32 cases)"],"in_progress":[],"blockers":[]}' \
--metadata '{"repo":"my-web","branch":"feature/notifications","agent_tool":"cursor","agent_name":"cursor","model":"claude-sonnet-4-20250514"}'Why: Describes what users get, lists all deliverables, marks as milestone.
---
12. Multi-step task (milestone)
Weak:
dailybot agent update "Completed a deep work plan with multiple tasks" \
--name "codex" \
--milestoneStrong:
dailybot agent update \
"Completed the auth refactor — JWT tokens now work across all services with centralized middleware validation, eliminating per-service token handling." \
--name "codex" \
--milestone \
--json-data '{"completed":["JWT middleware implementation","Token validation service","Session migration script","Integration tests (24 cases)","API documentation update"],"in_progress":[],"blockers":[]}' \
--metadata '{"repo":"my-api","branch":"feature/auth","agent_tool":"codex","agent_name":"codex","model":"o3"}'Why: Describes the outcome and lists specific deliverables. No plan names or task IDs.
---
13. Feature with blockers
Weak:
dailybot agent update "Working on deployment, having some issues" \
--name "cursor"Strong:
dailybot agent update \
"Implemented the staging deployment pipeline — builds and tests are automated, but the final deploy step is blocked by a Docker image issue." \
--name "cursor" \
--json-data '{"completed":["Build automation","Test runner integration","Environment configuration"],"in_progress":["Deploy step automation"],"blockers":["Docker base image missing libpq-dev — needs infrastructure team to update"]}' \
--metadata '{"repo":"my-api","branch":"feature/deploy","agent_tool":"cursor","agent_name":"cursor","model":"claude-sonnet-4-20250514"}'Why: Clear about what's done, what's pending, and exactly what's blocking.
---
14. Deployment (milestone)
Weak:
dailybot agent update "Deployed to production" \
--name "windsurf" \
--milestoneStrong:
dailybot agent update \
"Deployed the new billing system to production — subscription management is now fully automated with Stripe webhook handling." \
--name "windsurf" \
--milestone \
--metadata '{"repo":"billing-service","branch":"main","agent_tool":"windsurf","agent_name":"windsurf","model":"claude-sonnet-4-20250514"}'Why: Says what was deployed and what it means for the product.
---
15. Analysis (no milestone)
Weak:
dailybot agent update "Completed analysis" \
--name "copilot"Strong:
dailybot agent update \
"Completed the API performance audit — identified 3 N+1 query issues and a missing database index that account for 80% of p95 latency. Documented findings with fix recommendations." \
--name "copilot" \
--json-data '{"completed":["Query analysis across 12 endpoints","N+1 detection and documentation","Missing index identification","Fix recommendation document"],"in_progress":[],"blockers":[]}' \
--metadata '{"repo":"my-api","branch":"main","agent_tool":"copilot","agent_name":"copilot","model":"gpt-4o"}'Why: Specific findings, quantified impact, clear deliverables — even though no code was written.
---
The Standup Test — Quick Calibration
Before sending any report, ask: "Would this be worth saying in a real standup?"
| Report | Worth saying? |
|---|---|
| "Implemented the notification preferences system" | Yes |
| "Fixed a typo in a test file" | No |
| "Deployed the new auth middleware to staging" | Yes |
| "Updated a lockfile" | No |
| "Built the user preferences API with full test coverage" | Yes |
| "Read some code and explored the codebase" | No |
| "Completed the 8-task auth refactor with JWT across all services" | Yes |
| "3 files modified" | No |
| "Drafted the Q3 product roadmap with prioritized initiatives" | Yes |
| "Had a conversation with no conclusions" | No |
Hook Enforcement — Deterministic Report Reminders
Prompt instructions (the `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 groupfirst ships in 1.12.0 — release notes).
Check with dailybot --version; if older, ask the developer to rundailybot upgrade once. Hooks installed against an older CLI failgracefully (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 <fmt> | 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 <fmt> | 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.
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. 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`, 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 <repo>/.claude/settings.json (commit it so the whole team gets autonomous reporting).
Merge this into the existing JSON (create the file if missing):
{
"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 <repo>/.cursor/hooks.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 |
| GitHub Copilot | .github/hooks/dailybot.json (repo) | agentStop | docs.github.com — hooks reference |
| Gemini CLI | .gemini/settings.json or ~/.gemini/settings.json | AfterAgent | geminicli.com/docs/hooks |
| OpenCode | plugin in ~/.config/opencode/plugins/ | session.idle | opencode.ai/docs/plugins |
| Windsurf | .windsurf/hooks.json | post_cascade_response (cannot inject context — run-only) | docs.devin.ai — hooks |
Cline has no end-of-turn hook as of this writing — rely on the `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 <n> |
| Harness errors on hook output | Wrong --format — claude/cursor emit JSON, generic is plain text |
When to Report — Trigger Rules
This guide defines when to send a Dailybot progress report. The system uses objective, binary conditions — no subjective judgment required.
Report Triggers
Send a progress report when either condition is met:
1. Task completed
You finished a discrete task or subtask — a todo item, a user-requested change, a bug fix, a feature, a refactor, a test suite, a deployment.
The key test is structural: is the unit of work done? If you checked off a task or delivered what was asked, report it.
2. Broad edit
You modified 3 or more files in a single batch of edits. This catches meaningful cross-cutting changes even when no explicit "task" was defined.
User override
If the developer explicitly says "report this to Dailybot" or "send an update", always report regardless of the conditions above.
Milestone Rule
Mark a report as a milestone only when the top-level task is fully completed — all subtasks are done and the entire requested piece of work is wrapped up.
Individual subtask completions are regular reports, not milestones. If the developer explicitly asks for a milestone, always honor it.
Aggregation Rule
If you completed multiple related changes, combine them into one report. Don't send 3 reports for parts of one feature.
Instead of:
- "Updated the user model"
- "Added the preferences endpoint"
- "Wrote tests for preferences"
Send one:
- "Built the user preferences system — new data model, API endpoint, and full test coverage."
Edge Cases
"I completed a task AND answered some questions"
Report the task completion. Ignore the Q&A — only the trigger-meeting part matters.
"I did many small edits across files"
If 3+ files were modified, report regardless of how small each individual edit was. The report content should describe the aggregate outcome.
"The developer asked me to report"
Always honor explicit requests, even if neither trigger condition is met.
"I already reported recently"
If you sent a report less than 30 minutes ago for the same logical task, consider aggregating with the next one rather than sending back-to-back reports.
"I'm mid-task, not done yet"
Do not report incomplete work just because you edited 3+ files as part of an ongoing task. The broad-edit trigger applies to a completed batch of edits, not work-in-progress mid-stream. Wait until the subtask or edit batch is done.
Auto-Activation Triggers
This file contains the exact trigger templates for each supported agent. A trigger is a small always-on instruction that tells the agent to invoke 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.0the harness can enforce reporting deterministically via lifecycle hooks;
see `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 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 later:
<!-- dailybot-auto-activation: BEGIN -->
...content...
<!-- dailybot-auto-activation: END (delete this block to disable) -->To uninstall on any agent, search for dailybot-auto-activation in the file listed below and delete from BEGIN to END (inclusive).
---
Cursor
Cursor uses .mdc rule files with YAML frontmatter.
Path: ~/.cursor/rules/dailybot.mdc
Create this file with the following content (the file existing IS the opt-in marker — to uninstall, delete the file):
---
description: Invoke Dailybot skills for progress reporting, message checking, and team coordination
alwaysApply: true
---
<!-- dailybot-auto-activation: BEGIN — delete this file to disable -->
Send a progress report to Dailybot after each of the following: (a) completing a discrete task or subtask, or (b) after any batch of edits that modifies 3 or more files. Compose a standup-style update describing what changed and why. Use the `dailybot-report` skill to send the report.
At the start of a work session, check for pending messages from the team using the `dailybot-messages` skill.
During long sessions (15+ minutes), send periodic health checks using the `dailybot-health` skill.
<!-- dailybot-auto-activation: END -->Verify: test -f ~/.cursor/rules/dailybot.mdc
---
Claude Code
Claude Code reads CLAUDE.md files for persistent instructions.
Path: ~/.claude/CLAUDE.md
Append the following block to the end of the file (create the file if it doesn't exist):
<!-- dailybot-auto-activation: BEGIN -->
## Dailybot
Send a progress report to Dailybot after each of the following: (a) completing a discrete task or subtask, or (b) after any batch of edits that modifies 3 or more files. Compose a standup-style update describing what changed and why. Use the dailybot-report skill to send the report.
At the start of a work session, check for pending messages using the dailybot-messages skill. During long sessions, send periodic health checks using the dailybot-health skill.
User command: /dailybot_report. Agent-only skills: dailybot-messages, dailybot-email, dailybot-health.
<!-- dailybot-auto-activation: END (delete this block to disable) -->Verify: grep -q "dailybot-auto-activation" ~/.claude/CLAUDE.md 2>/dev/null
---
OpenAI Codex
Codex reads AGENTS.md files for persistent instructions.
Path: ~/.codex/AGENTS.md
Append the following block to the end of the file (create the file if it doesn't exist):
<!-- dailybot-auto-activation: BEGIN -->
## Dailybot
Send a progress report to Dailybot after each of the following: (a) completing a discrete task or subtask, or (b) after any batch of edits that modifies 3 or more files. Compose a standup-style update describing what changed and why. Use the dailybot-report skill to send the report.
At the start of a work session, check for pending messages using the dailybot-messages skill. During long sessions, send periodic health checks using the dailybot-health skill.
User-invocable: dailybot-report. Agent-only: dailybot-messages, dailybot-email, dailybot-health.
<!-- dailybot-auto-activation: END (delete this block to disable) -->Verify: grep -q "dailybot-auto-activation" ~/.codex/AGENTS.md 2>/dev/null
---
Windsurf
Windsurf uses global rules managed through Settings, or files in .windsurf/rules/.
Preferred: Ask the developer to add a global rule through Settings > Cascade > Rules with activation mode Always On and the content below.
Alternative — if the developer prefers a file, create a workspace rule (deleting the file disables the trigger):
Path: .windsurf/rules/dailybot.md
---
trigger: always_on
---
<!-- dailybot-auto-activation: BEGIN — delete this file to disable -->
Send a progress report to Dailybot after each of the following: (a) completing a discrete task or subtask, or (b) after any batch of edits that modifies 3 or more files. Compose a standup-style update describing what changed and why. Use the `dailybot-report` skill to send the report.
At the start of a work session, check for pending messages using the `dailybot-messages` skill. During long sessions, send periodic health checks using the `dailybot-health` skill.
<!-- dailybot-auto-activation: END -->Verify: Ask the developer if Dailybot appears in their Windsurf rules, or check test -f .windsurf/rules/dailybot.md
---
GitHub Copilot
Copilot reads AGENTS.md files for agent instructions.
Path: ~/.agents/AGENTS.md
Append the following block to the end of the file (create the file if it doesn't exist):
<!-- dailybot-auto-activation: BEGIN -->
## Dailybot
Send a progress report to Dailybot after each of the following: (a) completing a discrete task or subtask, or (b) after any batch of edits that modifies 3 or more files. Compose a standup-style update describing what changed and why. Use the dailybot-report skill to send the report.
At the start of a work session, check for pending messages using the dailybot-messages skill. During long sessions, send periodic health checks using the dailybot-health skill.
User-invocable: dailybot-report. Agent-only: dailybot-messages, dailybot-email, dailybot-health.
<!-- dailybot-auto-activation: END (delete this block to disable) -->Verify: grep -q "dailybot-auto-activation" ~/.agents/AGENTS.md 2>/dev/null
---
Cline
Cline reads .clinerules files for persistent instructions.
Path: ~/.cline/.clinerules
Append the following block to the end of the file (create the file if it doesn't exist):
<!-- dailybot-auto-activation: BEGIN -->
## Dailybot
Send a progress report to Dailybot after each of the following: (a) completing a discrete task or subtask, or (b) after any batch of edits that modifies 3 or more files. Compose a standup-style update describing what changed and why. Use the dailybot-report skill to send the report.
At the start of a work session, check for pending messages using the dailybot-messages skill. During long sessions, send periodic health checks using the dailybot-health skill.
<!-- dailybot-auto-activation: END (delete this block to disable) -->Verify: grep -q "dailybot-auto-activation" ~/.cline/.clinerules 2>/dev/null
---
OpenClaw
OpenClaw uses the AgentSkills-compatible SKILL.md format natively. No trigger file is needed — OpenClaw loads skills automatically on every eligible session based on gating rules in the frontmatter metadata field.
Install via ClawHub (recommended):
openclaw skills install dailybotInstall manually:
git clone https://github.com/DailybotHQ/agent-skill.git <workspace>/skills/dailybotConfigure API key in ~/.openclaw/openclaw.json:
{
"skills": {
"entries": {
"dailybot": {
"enabled": true,
"apiKey": { "source": "env", "provider": "default", "id": "DAILYBOT_API_KEY" }
}
}
}
}The /dailybot router and /dailybot_report register as slash commands. The messages, email, and health skills are agent-only (not user-invocable) and activate autonomously. No trigger setup required.
---
Gemini CLI
Gemini CLI reads GEMINI.md for persistent instructions.
Path: ~/.gemini/GEMINI.md
Append the following block to the end of the file (create if it doesn't exist):
<!-- dailybot-auto-activation: BEGIN -->
## Dailybot
Send a progress report to Dailybot after each of the following: (a) completing a discrete task or subtask, or (b) after any batch of edits that modifies 3 or more files. Compose a standup-style update describing what changed and why. Use the dailybot-report skill to send the report.
At the start of a work session, check for pending messages using the dailybot-messages skill. During long sessions, send periodic health checks using the dailybot-health skill.
User-invocable: dailybot-report. Agent-only: dailybot-messages, dailybot-email, dailybot-health.
<!-- dailybot-auto-activation: END (delete this block to disable) -->Verify: grep -q "dailybot-auto-activation" ~/.gemini/GEMINI.md 2>/dev/null
---
Skill installation paths
After running ./setup.sh, symlinks are created for each sub-skill:
| Agent | Pack path | Symlinked sub-skills |
|---|---|---|
| Cursor | ~/.cursor/skills/dailybot/ | ~/.cursor/skills/dailybot-report/, -messages/, -email/, -health/ |
| Claude Code | ~/.claude/skills/dailybot/ | ~/.claude/skills/dailybot-report/, -messages/, -email/, -health/ |
| OpenAI Codex | ~/.codex/skills/dailybot/ | ~/.codex/skills/dailybot-report/, -messages/, -email/, -health/ |
| Windsurf | ~/.codeium/windsurf/skills/dailybot/ | same pattern |
| GitHub Copilot | ~/.copilot/skills/dailybot/ | same pattern |
| Cline | ~/.cline/skills/dailybot/ | same pattern |
| Gemini CLI | ~/.gemini/skills/dailybot/ | same pattern |
| OpenClaw | <workspace>/skills/dailybot/ | native discovery, no symlinks needed |
Cursor also reads from ~/.claude/skills/ and ~/.codex/skills/ for compatibility. Windsurf also reads from ~/.agents/skills/ for compatibility. Copilot also reads from ~/.claude/skills/ and ~/.agents/skills/ for compatibility.
Writing Guide — How to Compose Reports Teams Value
Every report you send appears in Dailybot alongside updates from human team members. Your report should be indistinguishable from a human's standup update.
The Human-First Principle
The developer who works with you directed the effort, made the decisions, and is accountable for the result. Your report reflects their accomplishment, not yours.
Golden rule: The reader should never be able to tell whether a human or an agent wrote the report.
Report Structure
Every report follows the same pattern:
[What was accomplished] — [why it matters or what it enables].Lead with the outcome, then connect it to impact. One to three sentences maximum.
Sentence Construction
Action verbs by work type
| Work type | Strong verbs |
|---|---|
| New feature | Built, Implemented, Added, Shipped, Created |
| Bug fix | Fixed, Resolved, Corrected, Patched |
| Refactor | Refactored, Redesigned, Restructured, Simplified, Migrated |
| Tests | Added test coverage for, Tested, Validated |
| Documentation | Documented, Wrote documentation for |
| Performance | Optimized, Improved, Reduced latency for, Accelerated |
| Configuration | Configured, Set up, Enabled, Integrated |
| Analysis | Analyzed, Investigated, Identified, Mapped out |
| Deployment | Deployed, Released, Shipped, Launched |
What to emphasize
Emphasize:
- User-facing outcomes ("users can now...")
- Business value ("prevents duplicate charges...")
- Scope of the work ("12 endpoints", "full test suite with 32 cases")
- What changed from the user's perspective
Do not emphasize:
- Number of files changed
- Lines of code added or removed
- Internal implementation details
- Which libraries or tools were used (unless that IS the deliverable)
Templates by Work Type
Feature
Built/Implemented [what] — [what it enables for users or the team]."Implemented notification preferences — users can now choose which alerts they receive via email vs. in-app."
Bug fix
Fixed [user-facing problem] — [brief cause or what was going wrong]."Fixed an issue where team members in different timezones saw incorrect standup deadlines."
Refactor
Refactored [what] to [improvement] — [benefit or what this enables]."Refactored the authentication flow to use JWT tokens — improves session management and enables cross-service auth."
Test coverage
Added test coverage for [what] — [scope or what scenarios are now covered]."Added test coverage for the webhook retry system — 12 cases covering timeout, auth failure, and payload validation."
Documentation
Documented [topic] — [what readers can now find or understand]."Documented the API rate limiting system — configuration options, default limits, and troubleshooting steps."
Performance
Optimized [what] — [measurable improvement or user-facing benefit]."Optimized the dashboard query — page now loads in under 500ms instead of 3 seconds for large teams."
Deployment
Deployed [what] to [where] — [what is now live or available]."Deployed the new billing system to production — subscription management is now fully automated."
Analysis or research
Completed [what] — [key findings or what decisions it enables]."Completed the API performance audit — identified 3 N+1 queries and a missing index that account for 80% of latency."
Multiple related changes
[Summary of the overall effort]: [most important item]. Also [secondary items]."Made several improvements to the standup flow: added timezone-aware scheduling and improved reminder formatting. Also fixed a layout issue on mobile."
Forbidden Patterns
Never include these in a report message:
| Pattern | Example | Why it's wrong |
|---|---|---|
| File paths | app/services/auth.py | Nobody reads file paths in a standup |
| Git statistics | 3 files changed, +127 -12 | Meaningless without context |
| Raw commit messages | feat(scope): description | Commit syntax is for git, not humans |
| Branch names | pushed to dev, merged to main | Internal workflow details |
| Agent attribution | Agent completed..., I implemented... | Violates the human-first principle |
| Deferring to git | see git log for details | Reports must be self-contained |
| Jargon without context | resolved hydration mismatch | Most team members won't understand |
| Plan or task IDs | PLAN_auth_refactor, task-3 | Internal identifiers, not outcomes |
| Non-English text | Se corrigió un error | All reports must be in English |
| Vague fallbacks | Updated code, Made changes | If you can't be specific, don't report |
Structured Data Guidelines
Use --json-data when a report covers three or more distinct deliverables.
Writing good items
Good — concise, outcome-oriented:
- "JWT authentication endpoint"
- "Token refresh with expiry handling"
- "Integration tests (24 cases)"
- "API documentation update"
Bad — vague or overly technical:
- "Updated files"
- "Refactored code"
- "app/auth/middleware/jwt_validator.py"
- "Fixed the thing"
When structured data helps
- Multi-deliverable features (3+ distinct pieces)
- Task or plan completions with multiple outputs
- When the individual items add clarity beyond the message alone
When to skip structured data
- Single bug fix (the message says everything)
- One-item reports (structured data adds noise)
- When every item would just repeat the message differently
Rate Limiting
Quality over quantity. One rich, specific report is worth more than ten shallow ones.
- If you completed related changes, aggregate into one report
- Aim for roughly 10 meaningful reports per day at most, not 100
- If the last report was less than 30 minutes ago, consider waiting and combining
- Back-to-back reports about the same feature should always be merged
Co-Authors
Do not add co-authors on your own initiative. The Dailybot backend automatically credits the authenticated developer.
Only use --co-authors when the developer explicitly says to credit someone else. The flag accepts email addresses or user UUIDs. Never guess email addresses.
For multiple co-authors, either repeat the flag or use a comma-separated list:
--co-authors alice@co.com --co-authors bob@co.com
--co-authors "alice@co.com,bob@co.com"Dailybot Authentication
This file is shared across all Dailybot skills. Every skill references it for auth setup before performing its primary action.
Run these checks in order. Stop at the first failure. Present one clear action to the developer at a time during interactive login — never ask multiple questions at once.
---
1. Check Dailybot CLI is installed
command -v dailybotIf dailybot is found, verify it runs:
dailybot --version 2>&1 || dailybot status --auth 2>&1If the CLI is not installed — confirm, then run the universal installer
Installing software on the developer's machine is a security-relevant action. The first time you need to install the CLI in a session, show the proposed command and proceed only after explicit confirmation. Do not re-prompt for later invocations in the same session — once the developer has confirmed, treat that as session-wide consent.
[!NOTE]
The Dailybot CLI ships two installer entry points that pair with
SHA-256 sidecar files. Pick the one that matches the developer's shell:
- `install.sh` — Linux, macOS, WSL2, Git Bash, Docker, CI. Auto-detects
the OS internally and routes to brew install dailybothq/tap/dailyboton macOS, the prebuilt PyInstaller binary on Linux x86_64, or
pipx/uv tool/pip --usereverywhere else.
- `install.ps1` — only for native Windows PowerShell when WSL2 and
Git Bash are unavailable. Wrapspipx/uv tool/pip --userand
requires Python 3.10+ on PATH. There is no native Windows .exe.>
If the developer is on Windows but has WSL2 or Git Bash, prefer
install.sh — it has broader testing coverage.Primary path: defense-in-depth verified install (Linux, macOS, WSL2, Git Bash, Docker, CI)
Show the developer this prompt the first time:
"I'd like to install the Dailybot CLI. The command I'll run is:
>
```bash
curl -fsSL https://cli.dailybot.com/install.sh -o /tmp/install.sh
curl -fsSL https://raw.githubusercontent.com/DailybotHQ/cli/main/install.sh -o /tmp/install.sh.gh
diff -q /tmp/install.sh /tmp/install.sh.gh || { echo "Install script on Cloudflare CDN does not match the GitHub source — refusing to install." >&2; exit 1; }
curl -fsSL https://cli.dailybot.com/install.sh.sha256 -o /tmp/install.sh.sha256
( cd /tmp && shasum -a 256 -c install.sh.sha256 ) || exit 1
bash /tmp/install.sh
```
>
The script auto-detects your OS and uses Homebrew on macOS, the prebuilt
binary on Linux, or pipx/uv/pip elsewhere. To uninstall or upgrade later,
the CLI itself owns those workflows (dailybot upgrade). **Should Iproceed?** (yes / no)"
The flow has three independent integrity checks before the script executes — any one of them aborts the install:
1. Cross-origin diff. The script is fetched twice — once from cli.dailybot.com (Cloudflare CDN) and once from raw.githubusercontent.com/DailybotHQ/cli/main/install.sh (GitHub's public-source endpoint). They must be byte-identical. A coordinated compromise that flips both Cloudflare AND GitHub's raw output for the same file would be required to defeat this; either alone is caught. 2. SHA-256 sidecar match. The .sha256 companion file (also served by cli.dailybot.com, regenerated on every CLI release by sync-installer-checksums.yml) must match the script's actual hash. This catches CDN cache corruption and stale-deploy scenarios. 3. (Optional) Cosign signature verification. If cosign is on PATH AND the CLI repo has published install.sh.sig + install.sh.cert (signed by DailybotHQ/cli GitHub Actions OIDC, recorded in the public Sigstore transparency log), the agent should also run:
if command -v cosign >/dev/null 2>&1 && curl -fsI https://cli.dailybot.com/install.sh.sig >/dev/null 2>&1; then
curl -fsSL https://cli.dailybot.com/install.sh.sig -o /tmp/install.sh.sig
curl -fsSL https://cli.dailybot.com/install.sh.cert -o /tmp/install.sh.cert
cosign verify-blob \
--certificate-identity-regexp 'https://github.com/DailybotHQ/cli/.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
--signature /tmp/install.sh.sig \
--certificate /tmp/install.sh.cert \
/tmp/install.sh || exit 1
fiThis binds the script to GitHub's OIDC identity, anchored in the transparency log. Until the CLI repo publishes .sig/.cert files the step is a no-op (the curl -fsI probe falls through), so the agent never errors on it being absent.
If any check fails, abort and warn the developer — never fall back silently. If install.sh.sha256 itself returns non-200 (rare CDN incident), warn the developer and offer two choices: (a) re-fetch later, or (b) skip CLI install and use the HTTP API path below. Do not run the script unverified.
Threat-model rationale and operational controls (HSTS preload,
Certificate Transparency monitoring, the public Sigstore log) are
documented in `SECURITY.md` under
"Supply-chain integrity for the CLI installer".
Native Windows PowerShell (only when WSL2 / Git Bash unavailable)
$tmp = "$env:TEMP\dailybot-install"
New-Item -ItemType Directory -Force -Path $tmp | Out-Null
Invoke-WebRequest "https://cli.dailybot.com/install.ps1" -OutFile "$tmp\install.ps1"
Invoke-WebRequest "https://cli.dailybot.com/install.ps1.sha256" -OutFile "$tmp\install.ps1.sha256"
$expected = (Get-Content "$tmp\install.ps1.sha256").Split(" ")[0]
$actual = (Get-FileHash "$tmp\install.ps1" -Algorithm SHA256).Hash.ToLower()
if ($expected -ne $actual) { throw "SHA-256 mismatch — refusing to run install.ps1" }
& "$tmp\install.ps1"install.ps1 requires Python 3.10+ on PATH (it shells out to pipx / uv tool / pip --user). If the developer is on Windows + WSL2 or Git Bash, the bash path above is preferred — broader test coverage and no Python prerequisite.
Manual control (developer prefers their own package manager)
If the developer would rather install via their own toolchain instead of the script, all three produce the same dailybot binary:
- macOS:
brew install dailybothq/tap/dailybot - Cross-platform Python (recommended for raw control):
pipx install dailybot-cli or uv tool install dailybot-cli
- Last resort:
pip install --user dailybot-cli
Use these when the developer says "I'd rather use brew/pipx" or when running in an environment that already has one of them set up. Don't surface them as the default — the universal script covers more cases and gets the same result. Do not pip install dailybot-cli against the system Python without explicit user consent; the installer scripts already pick the right isolated path automatically.
Skipping consent prompts (CI / Docker / power users)
If DAILYBOT_AUTO_YES=1 is set in the environment, treat install consent as already given — run the verified install command directly without the interactive prompt. The SHA-256 check still runs and still aborts on mismatch. `DAILYBOT_AUTO_YES` does NOT skip email confirmations — those are mandatory regardless.
After any install attempt, re-check:
command -v dailybotIf dailybot is not on PATH after a successful install, surface the likely cause to the developer and stop — do not loop on retries:
- The shell may not have reloaded PATH (open a new terminal).
- On Linux, the user-site bin directory (
~/.local/bin) may not be on PATH. - pipx/uv shims may not yet be linked.
Upgrading later
The skill does not own upgrade logic. The CLI ships its own dailybot upgrade command (since v1.4.0) that auto-detects how the CLI was installed and either runs the right upgrade in a subprocess (pipx/uv/pip) or prints the exact command for installs the CLI shouldn't drive (Homebrew, prebuilt binary, editable). Tell the developer:
"To upgrade the Dailybot CLI later, run dailybot upgrade. To checkwhether you're on the latest version, run dailybot version --check."That's the entire upgrade story. Don't pin a version anywhere in the skill, don't reimplement upgrade detection, don't suggest re-running the installer to get a newer version.
If the CLI still cannot be installed
Stop trying installers. Briefly explain the limitation, then use the HTTP API path with DAILYBOT_API_KEY per `http-fallback.md`. Ask the developer to create an API key at Dailybot → Settings → API Keys and export it:
export DAILYBOT_API_KEY="<their-key>"Sandboxed environments, CI, or minimal containers may never get a working CLI — HTTP fallback is expected there.
---
2. Check authentication
dailybot status --auth 2>&1If already authenticated — skip to "3. Check agent profile."
If not authenticated, guide the developer through login one step at a time. Most developers already belong to a Dailybot organization through their team — always start with login, not registration.
The CLI checks credentials in this order: agent profile → DAILYBOT_API_KEY env var → stored key (dailybot config key=...) → login session.
OTP login flow
Start with only this question:
"To connect Dailybot, I need to log in with your account.
>
What email address do you use for Dailybot?
>
(If you'd rather do it yourself, run dailybot login in your terminal andlet me know when you're done.)"
If they prefer to handle it themselves — wait for confirmation, verify with dailybot status --auth, continue.
If they provide their email, proceed one step at a time:
1. dailybot login --email=<their-email> 2. Ask: "Check your email for a verification code from Dailybot. What's the code?" 3. dailybot login --email=<their-email> --code=<their-code> 4. If output lists multiple organizations, show the list and ask them to pick one 5. If needed: dailybot login --email=<their-email> --code=<their-code> --org=<selected-uuid> 6. Verify: dailybot status --auth
API key alternative
If the developer already has an API key, they can store it instead:
dailybot config key=<their-api-key>This persists the key on disk — no env var or login session needed afterward.
Self-registration (only when explicitly requested)
Only if login fails and they explicitly say they don't have an account — offer standalone registration:
"No problem — I can register a new Dailybot organization right from here.
What's a name for your organization?"
1. Ask for an org name and optionally a contact email 2. dailybot agent register --org-name "<org_name>" --agent-name "<agent_tool>" Or with email: dailybot agent register --org-name "<org_name>" --agent-name "<agent_tool>" --email <their-email> 3. The command creates an org, generates an API key, and saves an agent profile automatically 4. Output includes a claim URL — tell the developer: "Share this with your team admin to connect Dailybot to Slack, Teams, Discord, or Google Chat. It expires in 30 days." 5. Verify: dailybot status --auth
Never proactively suggest `dailybot agent register`. Only offer it if the developer clearly states they have no existing account.
Auth rules
- Never store the developer's email, verification code, or API key in any file you create
- If login fails, suggest they run
dailybot loginmanually in their terminal - If auth seems corrupted, suggest
dailybot logoutthen re-login - If they decline to authenticate now, skip the current skill entirely
- Auth issues must never block your primary work
---
3. Check agent profile
dailybot agent profiles 2>&1If a default profile exists — note the name. You can omit --name on subsequent CLI commands.
Repo profile takes precedence over the global default profile. If
the repo ships a.dailybot/profile.jsonwith anamefield, that
name wins over whatever the global default is — and you must omit
--name regardless of what the global default is. Same fordefault_metadata keys. Full rules:`shared/repo-profile.md`.
If no profile exists and authentication succeeded, create one automatically. This is metadata only (no install, no network call beyond the CLI command), so no separate confirmation is needed:
dailybot agent configure --name "<agent_tool>"Briefly confirm:
"Dailybot is ready. Your agent profile is set as <agent_tool>."
---
After Authentication
Once authenticated via CLI login, the CLI handles credentials automatically. No DAILYBOT_API_KEY is needed for CLI commands. HTTP fallback calls still require an API key — ask the user to generate one at Dailybot → Settings → API Keys.
---
4. User-Scoped Commands (Bearer Token Auth)
Some Dailybot features — check-ins, forms, kudos, and user directory — are scoped to the logged-in human's session, not to an agent identity. These commands use a Bearer token stored at ~/.config/dailybot/credentials.json after dailybot login.
Auth model distinction
| Scope | Auth method | How to set up | Used by |
|---|---|---|---|
| Agent endpoints | API key (X-API-KEY header) | dailybot config key=... or DAILYBOT_API_KEY env | dailybot agent update, dailybot agent health, dailybot agent email send |
| User endpoints | Bearer token (Authorization: Bearer <token>) | dailybot login (OTP email flow) | dailybot checkin, dailybot form, dailybot kudos, dailybot user |
Both auth paths can coexist — the CLI stores them separately. A developer can have both an API key (for agent operations) and a Bearer session (for user-scoped operations) active at the same time.
Checking user session status
dailybot status --auth 2>&1The output shows both the agent API key status and the Bearer session status. If the user session is missing or expired, guide through dailybot login using the OTP flow in Section 2 above.
Config directory override
The DAILYBOT_CONFIG_DIR environment variable overrides where all credential and config files are stored (default: ~/.config/dailybot/):
export DAILYBOT_CONFIG_DIR=/tmp/my-sandbox-config
dailybot login --email me@example.comThis is useful for development sandboxes, CI environments, or testing scenarios with isolated config directories. The directory is created automatically if it does not exist.
User-scoped commands fail without a Bearer session
If a developer tries to use dailybot checkin, dailybot form, dailybot kudos, or dailybot user with only an API key and no login session, the CLI exits with code 3 (not authenticated). Guide them through dailybot login — these commands require the human's own session, not an agent key.
#!/usr/bin/env bash
# context.sh — shared context detection for all Dailybot skills.
# Detects the current coding environment and outputs JSON for Dailybot metadata.
# Compatible with: Claude Code, Codex CLI, Cursor, Gemini CLI, OpenClaw, bare shell.
#
# Usage: bash context.sh
# Output: {"repo":"...","branch":"...","agent_tool":"...","agent_name":"..."}
#
# Per-repo opt-out:
# If `.dailybot/disabled` exists in the working repo root (or any parent),
# this script exits silently with code 0 and produces no output. Sub-skills
# should treat empty output as "skip telemetry for this repo."
#
# Manual fallback (when this script can't run):
# repo: git remote get-url origin 2>/dev/null | sed 's|.*/||;s|\.git$||'
# branch: git branch --show-current 2>/dev/null
# If git fails, use the current folder name for repo and "unknown" for branch.
# Assemble metadata JSON manually:
# {"repo":"<repo>","branch":"<branch>","agent_tool":"<tool>","agent_name":"<name>","model":"<model>"}
# Model examples: "claude-sonnet-4-6", "o3", "gemini-2.5-pro", "gpt-4o"
set -euo pipefail
# ── Per-repo opt-out check ───────────────────────────────────────────────────
# Walk up from $PWD looking for .dailybot/disabled. If found, exit silently.
check_disabled() {
local dir="$PWD"
while [[ "$dir" != "/" && -n "$dir" ]]; do
if [[ -f "$dir/.dailybot/disabled" ]]; then
return 0
fi
dir="$(dirname "$dir")"
done
return 1
}
if check_disabled; then
exit 0
fi
# ── Repo name ────────────────────────────────────────────────────────────────
REPO=""
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
REMOTE=$(git remote get-url origin 2>/dev/null || echo "")
if [[ -n "$REMOTE" ]]; then
REPO="${REMOTE##*/}"
REPO="${REPO%.git}"
fi
fi
if [[ -z "$REPO" ]]; then
REPO=$(basename "$PWD")
fi
# ── Branch ───────────────────────────────────────────────────────────────────
BRANCH=$(git branch --show-current 2>/dev/null || echo "")
if [[ -z "$BRANCH" ]]; then
BRANCH="unknown"
fi
# ── Agent detection ──────────────────────────────────────────────────────────
# Priority: explicit env var > vendor env vars > parent process basename > unknown.
# We deliberately avoid `ps aux | grep <name>` because it produces false
# positives on any unrelated process whose command line contains the substring.
AGENT_TOOL="unknown"
AGENT_NAME="unknown"
# 1) Explicit override (any agent or wrapper can set this).
if [[ -n "${DAILYBOT_AGENT_TOOL:-}" ]]; then
AGENT_TOOL="$DAILYBOT_AGENT_TOOL"
AGENT_NAME="${DAILYBOT_AGENT_NAME:-$AGENT_TOOL}"
fi
# 2) Vendor env vars (set by the harness itself).
if [[ "$AGENT_TOOL" == "unknown" ]]; then
if [[ -n "${CLAUDE_PLUGIN_ROOT:-}" || -n "${CLAUDECODE:-}" ]]; then
AGENT_TOOL="claude-code"; AGENT_NAME="claude-code"
elif [[ -n "${CODEX_SESSION_ID:-}" || -n "${CODEX_HOME:-}" ]]; then
AGENT_TOOL="codex-cli"; AGENT_NAME="codex-cli"
elif [[ -n "${CURSOR_SESSION_ID:-}" || -n "${CURSOR_TRACE_ID:-}" ]]; then
AGENT_TOOL="cursor"; AGENT_NAME="cursor"
elif [[ -n "${OPENCLAW_SESSION:-}" ]]; then
AGENT_TOOL="openclaw"; AGENT_NAME="openclaw"
elif [[ -n "${GEMINI_SESSION_ID:-}" ]]; then
AGENT_TOOL="gemini-cli"; AGENT_NAME="gemini-cli"
elif [[ -n "${WINDSURF_SESSION_ID:-}" ]]; then
AGENT_TOOL="windsurf"; AGENT_NAME="windsurf"
fi
fi
# 3) Parent process basename (only when env vars don't pin the agent).
# Match `comm` (executable basename) — never substring-match across argv.
if [[ "$AGENT_TOOL" == "unknown" ]]; then
PARENT_COMM=$(ps -o comm= -p "$PPID" 2>/dev/null || true)
case "$(basename "${PARENT_COMM:-}")" in
claude|claude-code) AGENT_TOOL="claude-code"; AGENT_NAME="claude-code" ;;
codex|codex-cli) AGENT_TOOL="codex-cli"; AGENT_NAME="codex-cli" ;;
cursor) AGENT_TOOL="cursor"; AGENT_NAME="cursor" ;;
openclaw) AGENT_TOOL="openclaw"; AGENT_NAME="openclaw" ;;
gemini) AGENT_TOOL="gemini-cli"; AGENT_NAME="gemini-cli" ;;
windsurf) AGENT_TOOL="windsurf"; AGENT_NAME="windsurf" ;;
esac
fi
# 4) CI fallback for unattended runs.
if [[ "$AGENT_TOOL" == "unknown" ]]; then
if [[ -n "${CI:-}" || -n "${GITHUB_ACTIONS:-}" || -n "${CIRCLECI:-}" ]]; then
AGENT_TOOL="ci"
AGENT_NAME="ci-agent"
fi
fi
# ── Output ────────────────────────────────────────────────────────────────────
# Use jq when available (handles all control characters correctly). Fall back
# to python3, then to a hardened bash escaper that covers the characters most
# likely to break manual JSON construction.
emit_json() {
if command -v jq >/dev/null 2>&1; then
jq -cn \
--arg repo "$REPO" \
--arg branch "$BRANCH" \
--arg agent_tool "$AGENT_TOOL" \
--arg agent_name "$AGENT_NAME" \
'{repo:$repo, branch:$branch, agent_tool:$agent_tool, agent_name:$agent_name}'
return
fi
if command -v python3 >/dev/null 2>&1; then
REPO="$REPO" BRANCH="$BRANCH" AGENT_TOOL="$AGENT_TOOL" AGENT_NAME="$AGENT_NAME" \
python3 -c 'import json,os; print(json.dumps({"repo":os.environ["REPO"],"branch":os.environ["BRANCH"],"agent_tool":os.environ["AGENT_TOOL"],"agent_name":os.environ["AGENT_NAME"]}))'
return
fi
# Hardened bash fallback: escapes \ " and the most common control chars.
escape_json() {
local s="$1"
s="${s//\\/\\\\}"
s="${s//\"/\\\"}"
s="${s//$'\n'/\\n}"
s="${s//$'\r'/\\r}"
s="${s//$'\t'/\\t}"
s="${s//$'\b'/\\b}"
s="${s//$'\f'/\\f}"
printf '%s' "$s"
}
printf '{"repo":"%s","branch":"%s","agent_tool":"%s","agent_name":"%s"}\n' \
"$(escape_json "$REPO")" \
"$(escape_json "$BRANCH")" \
"$(escape_json "$AGENT_TOOL")" \
"$(escape_json "$AGENT_NAME")"
}
emit_json
Dailybot HTTP API Fallback
Use this path when the Dailybot CLI is unavailable (sandboxed environments, CI containers, or when the developer can't install it). Requires curl.
Base URL: https://api.dailybot.com Auth header: X-API-KEY: $DAILYBOT_API_KEY
The DAILYBOT_API_KEY environment variable must be set. If it's not, ask the developer to generate a key at Dailybot → Settings → API Keys and set it:
export DAILYBOT_API_KEY="<their-key>"---
Endpoints
| Method | Endpoint | Purpose |
|---|---|---|
POST | /v1/agent-reports/ | Submit an activity report |
POST | /v1/agent-health/ | Health check + receive pending messages |
GET | /v1/agent-health/?agent_name=<n> | Retrieve last health status |
GET | /v1/agent-messages/?agent_name=<n>&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). |
---
Common Patterns
POST request template
curl -s -X POST https://api.dailybot.com/v1/<endpoint>/ \
-H "X-API-KEY: $DAILYBOT_API_KEY" \
-H "Content-Type: application/json" \
-d '<json_payload>'GET request template
curl -s -X GET "https://api.dailybot.com/v1/<endpoint>/?<query_params>" \
-H "X-API-KEY: $DAILYBOT_API_KEY"---
Error Handling
- 401 Unauthorized — API key is invalid or expired. Ask the developer for a new key.
- 403 Forbidden — API key doesn't have the required scope. Check key permissions.
- 429 Too Many Requests — Rate limited. Slow down. Do not retry in a tight loop.
- Network failure — Warn briefly and continue with primary work. Do not enter a diagnostic loop.
All HTTP calls should be non-blocking. If a call fails, warn the developer and move on.
---
---
User-Scoped Endpoints (Bearer Token Auth)
The user-scoped commands (checkin, form, kudos, user) use a Bearer token instead of an API key. All other patterns (error handling, non-blocking behavior) remain the same.
Auth header: Authorization: Bearer $DAILYBOT_BEARER_TOKEN
The Bearer token is obtained via the OTP login flow (see `auth.md` Section 4).
Obtaining a Bearer token programmatically
# Step 1 — request OTP
curl -s -X POST https://api.dailybot.com/v1/cli/request-code/ \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com"}'
# Step 2 — verify OTP (returns token)
curl -s -X POST https://api.dailybot.com/v1/cli/verify-code/ \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","code":"123456"}'
# → {"token":"<bearer-token>","organization":"Org Name"}User-Scoped Endpoint Reference
| Method | Endpoint | Purpose |
|---|---|---|
GET | /v1/cli/status/ | List pending check-ins for the logged-in user |
POST | /v1/checkins/<followup_uuid>/responses/ | Complete a check-in |
GET | /v1/forms/?include=questions | List forms with question definitions |
POST | /v1/forms/<form_uuid>/responses/ | Submit a form response |
GET | /v1/users/ | List organization members (paginated) |
POST | /v1/kudos/ | Give kudos to a teammate |
Example requests
List pending check-ins
curl -s -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \
https://api.dailybot.com/v1/cli/status/Complete a check-in
curl -s -X POST \
-H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \
-H "Content-Type: application/json" \
https://api.dailybot.com/v1/checkins/<followup_uuid>/responses/ \
-d '{
"responses": [
{"uuid": "<question-uuid>", "index": 0, "response": "Done"}
],
"last_question_index": 0
}'List forms (with questions)
curl -s -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \
"https://api.dailybot.com/v1/forms/?include=questions"Submit a form response
curl -s -X POST \
-H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \
-H "Content-Type: application/json" \
https://api.dailybot.com/v1/forms/<form_uuid>/responses/ \
-d '{"content": {"<question_uuid>": "My answer"}}'List organization members
curl -s -H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \
https://api.dailybot.com/v1/users/Paginated — follow next URL until null (max 50 pages).
Give kudos
curl -s -X POST \
-H "Authorization: Bearer $DAILYBOT_BEARER_TOKEN" \
-H "Content-Type: application/json" \
https://api.dailybot.com/v1/kudos/ \
-d '{"receivers": ["<user-uuid>"], "content": "Great work!"}'User-Scoped Error Handling
Same HTTP status codes as agent endpoints, plus:
| Code | Exit | Meaning |
|---|---|---|
402 | 5 | Quota exhausted (form response limit) |
403 | 4 | Permission denied, self-kudos, or daily kudos limit |
406 | 4 | Daily kudos limit reached |
429 | 6 | Rate limited — 60 req/min |
---
API Reference
Full API documentation: https://api.dailybot.com/api/swagger/ Full agent API skill: https://api.dailybot.com/skill.md
Repo profile (.dailybot/profile.json) — mandatory pre-flight
Read this before constructing ANY `dailybot` CLI command from ANY Dailybot sub-skill (report, chat, kudos, email, forms, checkin, teams, health, messages). This is a single source of truth — sub-skills link here instead of duplicating the rules.
The Dailybot CLI honours a per-repository configuration file at <repo>/.dailybot/profile.json. When a developer commits this file, they are telling every agent that works inside the repo "use this identity and these defaults — don't pass them on the command line". If your CLI invocation also passes those values via flags, the flags silently override the repo file (per the auth-resolution order), and the developer's pin is bypassed — bug.
This pre-flight closes that gap. Run it once per turn (or once per work session if you cache it) — the answer is invariant for the duration you stay in the same repo.
---
The rule (one line)
Before constructing anydailybot <subcommand>command line, walk up from$PWDlooking for a.dailybot/directory. If.dailybot/profile.jsonexists in the closest ancestor, omit from your command every flag the profile already provides.
What "already provides" means concretely:
| Profile key | Effect | Omit from your command line |
|---|---|---|
name | Pins the agent display name | --name (and its short alias -n) |
profile | Pins a named profile slug from ~/.config/dailybot/agents.json | --profile (and its short alias -p) |
default_metadata.<key> | Each <key> is shallow-merged into every outgoing report's metadata, with your inline value winning if both are set | <key> from your --metadata / -d JSON object — pass only keys the profile does not set |
Anything else the profile may contain (future-proofing — the schema may grow) is still safe to ignore for your command line; the CLI itself reads the full file.
---
How to detect the repo profile (mandatory pre-flight)
You must do this inside the sub-agent / before issuing the command, not after. Two equivalent ways:
Shell one-liner (preferred — POSIX, no extra tools)
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
PROFILE="$ROOT/.dailybot/profile.json"
if [ -f "$PROFILE" ]; then
cat "$PROFILE"
fiIf the file exists you'll see its JSON; pick which flags to omit based on the keys present.
Programmatic (Python 3 — always available)
python3 - <<'PY'
import json, os, pathlib
cur = pathlib.Path.cwd()
for p in [cur, *cur.parents]:
f = p / ".dailybot" / "profile.json"
if f.is_file():
profile = json.loads(f.read_text())
print(f"REPO_PROFILE={f}")
print(f"PROFILE_NAME={profile.get('name','')}")
print(f"PROFILE_SLUG={profile.get('profile','')}")
for k in (profile.get('default_metadata') or {}):
print(f"DEFAULT_META_KEY={k}")
break
else:
print("REPO_PROFILE=")
PYRead the output and skip the corresponding flags.
Walk-up semantics — closest wins. If multiple ancestors have a.dailybot/profile.json(rare but legal), the one closest to$PWDwins. The CLI itself follows the same rule, so anything you would have done by hand is whatdailybotwill do at run time.
---
Worked example
A repo at /workspace ships:
{
"name": "CLI",
"default_metadata": { "repo": "cli" }
}An agent wants to send a Dailybot report from /workspace/some/subdir. Wrong (overrides the profile silently):
dailybot agent update "..." \
--name "Claude (Cursor)" \
--metadata '{"model":"claude-opus-4-7","repo":"cli"}'Why wrong: --name "Claude (Cursor)" silently overrides "CLI" from the profile. "repo":"cli" in --metadata is redundant (the profile already merges it) but not harmful.
Right (respects the profile):
dailybot agent update "..." \
--metadata '{"model":"claude-opus-4-7"}'Why right: no --name, so the profile's "CLI" wins. --metadata only carries keys the profile does not set (model); the CLI shallow-merges the profile's default_metadata.repo automatically. The outgoing report carries name="CLI", metadata={"repo":"cli","model":"claude-opus-4-7"}.
---
Why a repo profile exists
.dailybot/profile.json is the team's contract for how agents should identify themselves inside a given codebase. It is:
- Committed to git (visible to every team member and every CI agent)
- Credential-free by design —
.dailybot/profile.jsonMUST NOT contain akeyfield; if it does, the CLI hard-errors. Secrets live only in~/.config/dailybot/credentials.jsonor~/.config/dailybot/agents.jsonon the developer's machine. - Authoritative — it's how the repo owner says "reports from this codebase should appear as `<name>` with metadata `<defaults>` no matter which agent / which laptop / which CI runner issued them". Honouring it is how that contract is kept.
Ignoring it via a flag override defeats the whole point.
---
Sub-skill responsibilities
Every sub-skill that invokes dailybot agent <verb> (or any dailybot subcommand that consumes the agent identity) must:
1. Run this pre-flight on first use within a turn. 2. Drop --name, --profile, and the relevant --metadata keys from the constructed command according to the table above. 3. If the sub-skill's example commands show those flags (for readability / pedagogical reasons), they must be accompanied by an explicit "omit these if a repo profile sets them — see `shared/repo-profile.md`" note.
This applies to: dailybot-report, dailybot-chat, dailybot-kudos, dailybot-email, dailybot-forms, dailybot-checkin, dailybot-teams, dailybot-health, dailybot-messages. (Everything in the pack.)
---
What about .dailybot/ files other than profile.json?
The schema may grow. Today the only file the CLI reads from .dailybot/ is profile.json. If you find other files in .dailybot/, do not act on them — just leave them alone. A future skill-pack release will add specific guidance for any new file.
---
See also
- `shared/auth.md` — full authentication / profile resolution model (Bearer token, API key, profile slug, env var).
- CLI auth-resolution order — the per-field precedence the CLI implements (this doc is the agent-side mirror).
- CLI configuration reference — the full
.dailybot/profile.jsonschema, security rules, and migration notes.