daily-brief
Build the user's Daily Brief across personal work and every permitted company.
Skill by indigoai-us
Chalk Labs
Need help deploying daily-brief?
Chalk Labs sets up agents like this inside real teams: connected to your tools, tested on your data, with a human in the loop where it matters.
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/indigoai-us-daily-brief
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: devops, data, productivity, agent-building
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
- Runs as
- Python package
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/daily-brief
Tools it pre-approves 6
From allowed-tools in SKILL.md: the agent may use these without asking you each time.
Read,Write,Edit,Grep,Glob,Bash
What's inside
- Skill name
daily-brief- Description
- Build the user's Daily Brief across personal work and every permitted company. Reads the last brief and the user's brief preferences, sweeps sessions, PRs, CI and DMs (plus meeting signals, fleet and connected integrations when a company is bound), writes brief-data.json and brief.json with a launch prompt for every action, and reports status so the desktop app can notify the user. The person's first ready brief adds a welcome edition. Run by the main local bot when the user presses Create brief, or on a schedule.
- License
- MIT
- Allowed tools
- Read,, Write,, Edit,, Grep,, Glob,, Bash
- Instructions
- 426 lines in SKILL.md · view on GitHub
Before installing
- Ships executable scripts
- Pre-approves any shell command
Files (11)
- SKILL.md
- openai.yaml · agents/
- brief-sweep.py · scripts/
- brief_rank.py · scripts/
- dm-inbox-no-company.json · scripts/fixtures/
- housekeeping.py · scripts/
- local_sessions.py · scripts/
- test_brief_additions.py · scripts/
- test_brief_helpers.py · scripts/
- test_local_sessions.py · scripts/
- test_person_brief.py · scripts/
SKILL.md (first lines)
# /daily-brief
Builds one person's Daily Brief across personal work and every permitted company by default. The HQ desktop app starts this through the main local bot when the user presses **Create brief**. A person can also run it directly with `/daily-brief [--all|company|--personal] [--welcome] [--today YYYY-MM-DD]`.
An explicit personal brief (`--personal`) reads only what belongs to the person on this machine and in GitHub: work sessions, PRs, main-branch CI and personal DM messages (messages with no company). The company-only sources (meetings, meeting signals, fleet agents and integrations) are skipped and recorded as skipped, and housekeeping skips the doctor and sync checks. A new user with no company gets a useful first brief this way.
The output is a set of files the desktop app reads. This skill never posts, sends, merges or deploys anything.
## Inputs
| Input | Default |
|---|---|
| `--all` | Default: personal work plus every membership permitted by the session lock |
| `company` | Explicit first argument selects only that company |
| `--personal` | Build a brief with no company, even when the session has one bound |
| `--welcome` | Add the welcome edition (Welcome edition, below). On by default for the person’s first ready run in any mode |
| `today` | Today's local date |
| `run_id` | `--run-id <id>`, passed by the app. If missing, generate one as `brief-<YYYYMMDD-HHMMSS>` in local time |
Briefs are manually triggered, so several can exist per day. Each run gets its own folder, `workspace/brief/<run_id>/`. The `run_id` is `brief-<YYYYMMDD-HHMMSS>` in local time.
| File | Written when | What it is |
|---|---|---|
| `status.json` | At every step | Progress the app polls |
| `brief-data.json` | Step 3 | Raw normalized sweep output |
| `brief.json` | Step 4 | Synthesized items with prompts, read by the generator |
| `housekeeping.json` | Step 5 | Cleanup results and proposed cleanup actions |
When a run finishes, ready or failed, append one line to `workspace/brief/index.jsonl`. The desktop app's history navigator reads this file:
```json
{"run_id":"…","created_at":"…","finished_at":"…","duration_s":0,"window":{"from":"…","to":"…"},"state":"ready|failed","mode":"company|personal","company":"acme|null","catch_up":false,"lead":"…","counts":{"decisions":0,"shipped":0,"incidents":0,"carry":0,"recovered":0},"landed":false,"headline":"one plain line"}
```
`counts.shipped` is `brief-data.json.prs_summary.merged`, the same number the loader and the brief show. `counts.carry` and `counts.recovered` are the lengths of `items.carry` and `items.recovered`; `landed` is true when the run saw at least one merged PR or a release. `brief_rank.py --check` prints `index_counts` and `landed` ready to copy.
`status.json` shape:
```json
{"run_id":"…","state":"running|ready|failed","step":"…","progress":0.0,"started_at":"…","updated_at":"…","error":null,"sources":{}}
```
Write `status.json` before each step, and again after every source and integration check, so the app's progress bar stays truthful and keeps moving. Also keep a rolling `activity` list in `status.json`, newest last, capped at 12 entries. The app shows it under the sunrise so the user can see the run is alive:
```json
"activity":[{"at":"…","label":"Read 42 work sessions","state":"done","detail":"Oct 4–9"},{"at":"…","label":"Checking GitHub PRs","state":"running"}]
```
As each source lands, also update `findings` and `samples` in `status.json`. The app animates these as live counters and preview cards:
```json
"findings":{"signals":{"decision":0,"action_item":0,"risk":0,"commitment":0,"key_point":0},"sessions":0,"meetings":0,"dms":{"total":0,"need_you":0},"prs":{"merged":0,"opened":0,"open":0,"review_requested":0},"ci_red":0,"agents":{"total":0,"attention":0},"integrations":{}},
"samples":[{"kind":"decision","title":"Approve release-gate fix","company":"acme","at":"…"}]
```
`samples` holds at most 8 items, all from the active company only (`company` is null on a personal brief). Titles are short and plain. Never include DM body text: use the sender name and a summary instead.
`state` is `running`, `done`, `skipped` or `failed`. Labels are plain, user-facing language with real counts ("Found 31 DMs, 4 need you"), never commands or file paths. For other-company items, give counts only. Spread progress evenly across the sweep (0.25 → 0.7) by source, and across the integration checks. Read every timestamp from the clock in the same command that writes it.
## Step 1. Start
Write `status.json` with `state: running`, `step: "Checking your setup"` and `progress: 0.05`.
Check the session's company (`bash core/scripts/hq-session.sh current`). Never sweep a company the session is not locked to. The sweep reads the lock with `bash core/scripts/hq-session.sh get company_slugs` and refuses `--company` when that slug is outside the locked set.
- Default to a person brief (`--all`), including personal work and a section for each permitted company. `--company <slug>` and `--personal` remain explicit narrow modes.
- Membership inventory comes from the read-only `hq sync mode --show` table (the caller's memberships), intersected with `hq-session.sh get company_slugs`. Never widen the lock. Show every excluded membership as "not included: open HQ in that company to include it". Inventory/lock failures are visible source failures, never an invented empty membership list.
## Step 2. Load what we know about this person
- Read `personal/brief/brief-prefs.yaml`. If it is missing, create it from the defaults below. Besides `density`, `engine` and the VIP and mute lists, read the widget preferences the app's picker uses: `widget_weights` (kind → -2..2), `pinned_widgets` and `muted_widgets`. Step 4 copies them into `prefs_applied.widgets`.
- Find the last brief: the newest `ready` entry in `workspace/brief/index.jsonl` with `mode: person` for an all-company brief; for explicit narrow modes use the same company and mode. Skip lines that name another company. A line with no `company` field is an older run: use it only when its `brief.json` or `brief-data.json` has the same `company`. Read that run's `brief.json` too: its `items` are the carry-over candidates, and its `carry` rows give `carried_since` and `briefs` for chaining (Step 4, carry).
- **Deliberate reset.** If `workspace/brief/` is missing or holds no earlier run (no other run folder and no `ready` line in `index.jsonl`) and a sibling `workspace/brief-backup-*` folder exists, the owner reset brief history on purpose. It is not an incident, problem or decision, and never part of the lead. Treat the run as a first brief with no carry-over, label the activity "Starting fresh brief history", and leave the one-line note to housekeeping (Step 5). `brief-data.json.brief_history.reset_on_purpose` records the same check. A missing folder with no backup next to it is also only a housekeeping note, never the lead.
- **Window:** always the last 24 hours. The brief is a picture of the user's day, not a diff since the last run; a second run an hour later shows the same day again with the new items added. Only a catch-up brief widens the window: to the gap since the last brief, capped at 14 days.
- **Catch-up:** if the gap since the last brief is 3 days or more, set `catch_up: true`.
- Carry-over still uses the last brief: an item that was in it and is still open is marked `carry`, never dropped as "nothing new".
- Read the last brief's items. Anything still open becomes a carry-over candidate. Note what was launched or dismissed, from `personal/brief/brief-log.jsonl`.
Write status `step: "Reading your last brief"`, `progress: 0.15`.
## Step 3. Sweep
Run the sweep script. It records each source's success or failure, and never fills a gap with an invented value.
`--hours 24` is the brief's window: sessions, PRs and meetings from the last 24 hours. `--days 7` is only the per-day rollup (`days`) the week arc copies; it never widens the brief. For a catch-up brief (the user has been away 3 or more days) add `--catch-up` and set `--days` to the number of days since the last brief (at most 14), which keeps the meetings from that gap.
```bash
python3 -I .claude/skills/daily-brief/scripts/brief-sweep.py \
--all --days 7 --hours 24 --today <today> \
--hq-root "$PWD" --out workspace/brief/<run_id>/brief-data.json \
--status workspace/brief/<run_id>/status.json
```
For a narrow brief, replace `--all` with `--company <slug>` or `--personal`. Add `--welcome` to force the welcome edition.
On a company brief, PR search is limited to the company's GitHub owner: `--org <owner>`, or else the company's `github_org` in `companies/manifest.yaml`. With neither, and on a personal brief, it covers every owner the user's `gh` login can see. PRs from an owner that `companies/manifest.yaml` maps to another company (to any company, on a personal brief) are dropped and only counted in `prs_other`. The worktree scan treats worktrees the same way: they count in `detail.other` and their paths are never listed. Main-branch CI checks the repos of the user's own PRs in the window (most PRs first, at most 8); `--repos a,b` names them instead, as bare names (owner from `--org` or the PR rows) or owner-qualified names.
The script covers these sources:
| Source | Read through |
|---|---|
| Work sessions | Sessions come from `workspace/sessions` meta files plus the Claude and Codex transcripts (title, and kind you, agent or lane), for the last 24 hours (`--hours`). Other-company sessions are a count only. |
| Recorded meetings, plus each meeting's signals (company only) | `hq meetings list` and `get`. Per meeting, up to 5 decisions and 5 action items carry `text` (the signal's summary line, never transcript text), `owner`, and `mine` (the owner is the user, matched against `--me` or `git config user.name`) |
| DM inbox | `hq dm inbox`, then only this company's messages. A personal brief keeps messages with no company. Another company's messages are dropped and never written. Agent senders, with `agt_` IDs, are labeled. On a company brief, if the inbox page has messages and none carry a company slug field (`company`, `companySlug` or `company_slug` on the message or its channel), the source is skipped with `skipped_reason: "inbox has no company tag"`. `companyUid` is an id, not that field, so a page that only has it is still skipped. An empty inbox is a real empty result, not a skip. |
| Fleet agents (company only) | `hq agents list` |
| The user's PRs | `gh search prs --author @me` (with `author`), plus open PRs where the user is a requested reviewer (`--review-requested @me`, marked `review_requested: true` and `reviewRequests: ["@me"]`). Each row has `product`, `repo`, `repo_full` (the owner-qualified name), `authored_by_me` and `is_release`. Read-only |
| Main-branch CI health | `gh run list` |
Every source has an entry in `brief-data.json.sources` with `state`: `ok` (it ran), `failed` (it ran and broke; `note` and `error` hold one plain line such as "Couldn't read DMs."; the exception text goes to stderr only) or `skipped` (left out on purpose; `skipped_reason` says why). On a personal brief the company-only sources use `needs a company`. On a company brief, DMs use `inbox has no company tag` when the inbox page cannot be filtered by company. `ok` is true only for `state: ok`. A skipped source's top-level key is null. The top-level `mode` is `person`, `company` or `personal`. In person mode, `personal` holds personal sources and `companies.<slug>` holds each company sweep; `company` is null at the root. Each section has its own sources, window, derived summaries and deltas. Person history compares only previous `mode: person` runs, matching company sections by slug.
A skipped source is not a failure and not an empty result. The sweep writes its activity entry with `state: skipped`, a plain label (`Skipped DMs` for the inbox) and `detail` set to `skipped_reason`. It does not write `findings.dms` as `{total: 0}`, and it does not say there were no messages. The brief copies that: when `sources.dms.state` is `skipped`, write no DM decisions, waits or people from the inbox, and do not say the inbox was empty. One clause is enough: "DMs were skipped; the inbox has no company tag."
The script also writes `window.today`, `window.hours`, `window.prs_from`/`prs_to`, `window.attended_meetings_from` (= `sessions_from`, or the first catch-up day), and a top-level `prs_summary: {merged, opened, open, review_requested, median_merge_hours, by_product}` for the 24-hour window, counting only the user's own PRs. The loader's PR line uses the same function, so the app and the brief show the same numbers.
Derived data the sweep adds for the app's widgets (all computed, never estimated; every helper has a unit test in `scripts/test_brief_additions.py`):
| Block | What it carries |
|---|---|
| `sessions[]` | `project` (repo from the cwd), `product` (its human name), `cwd`, `last_activity`, `has_handoff` (a handoff thread record exists). Other-company rows keep only times and counts. On a personal brief the person's own rows, the ones bound to no company, carry `company: "personal"`; rows bound to any company count as `other` |From indigoai-us/hq-pack-core-skills, MIT.
More from indigoai-us/hq-pack-core-skills
- 0.565score
decision-desk
indigoai-us
The owner's decision desk for one /super-conductor link.
SkillAFreshness: AClaude Code +9 - 0.565score
architect
indigoai-us
Find shallow modules and propose deepening refactors, ranked with file refs; never edits code.
SkillAFreshness: AClaude Code +9 - 0.565score
conduct-join
indigoai-us
Join this already-running session to a /conduct session as one of its children, so the conductor can send it instructions and receive its reports.
SkillAFreshness: AClaude Code +9 - 0.561score
capacity
indigoai-us
Show usage, limits and reset times for every signed-in AI account (Claude, Codex, Grok) as a card in chat, or a table in a terminal.
SkillAFreshness: AClaude Code +9 - 0.561score
codebase-design
indigoai-us
Vocabulary for designing deep modules and clean interfaces.
SkillAFreshness: AClaude Code +9 - 0.561score
conduct
indigoai-us
Orchestrator mode: coordinate only; small tasks go to subagents, worker areas to standing hq lanes.
SkillAFreshness: AClaude Code +9 - 0.558score
adr
indigoai-us
Capture qualifying architecture decisions as ADRs in the right HQ or repo location.
SkillAFreshness: AClaude Code +9 - 0.558score
accept
indigoai-us
Accept HQ membership invites from a magic link or raw token.
SkillAFreshness: AClaude Code +9 - 0.558score
commit-main
indigoai-us
Commit every dirty file in the current repo, only when on main.
SkillAFreshness: AClaude Code +9 - 0.558score
decision-queue
indigoai-us
Resolve pending user decisions one at a time, one picker per item.
SkillAFreshness: AClaude Code +9 - 0.558score
clean-worktree
indigoai-us
Merge an HQ worktree branch back into local main, then remove the worktree and branch.
SkillAFreshness: AClaude Code +9 - 0.558score
convert-codex
indigoai-us
Add Codex support to older Claude-first HQ roots without breaking Claude setup.
SkillAFreshness: AClaude Code +9
Signals
- Stars
- 0
- Forks
- 0
- Open issues
- 0
- Last commit (this folder)
- Oct 23, 2026 (7 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from indigoai-us
- 0.565score
conduct-join
indigoai-us
Join this already-running session to a /conduct session as one of its children, so the conductor can send it instructions and receive its reports.
SkillAFreshness: AClaude Code +9 - 0.565score
decision-desk
indigoai-us
The owner's decision desk for one /super-conductor link.
SkillAFreshness: AClaude Code +9 - 0.565score
architect
indigoai-us
Find shallow modules and propose deepening refactors, ranked with file refs; never edits code.
SkillAFreshness: AClaude Code +9 - 0.561score
codebase-design
indigoai-us
Vocabulary for designing deep modules and clean interfaces.
SkillAFreshness: AClaude Code +9 - 0.561score
capacity
indigoai-us
Show usage, limits and reset times for every signed-in AI account (Claude, Codex, Grok) as a card in chat, or a table in a terminal.
SkillAFreshness: AClaude Code +9 - 0.561score
conduct
indigoai-us
Orchestrator mode: coordinate only; small tasks go to subagents, worker areas to standing hq lanes.
SkillAFreshness: AClaude Code +9
Done for you
Rather not set it up yourself?
Chalk Labs scopes, builds and runs agents for your team: the task audit, the eval harness, the integrations and the weekly ops report. Fixed scope, priced before we start.
See how we build AI agents →Read the case studies
Chalk Labs is a two-founder AI and growth studio. We build AI agents, CRMs and MVPs for Web3 and AI companies, and have shipped 50+ product and token launches.
- launches shipped
- 50+
- launches shipped
- media placements
- 500+
- media placements
- founders on every account
- 2
- founders on every account
Press we've placed: Forbes · CoinDesk · Decrypt · Cointelegraph · The Block
Rahil Jain, Co-founder, Chalk Labs. Ex-Goldman Sachs engineer. You talk to the person who builds it.
Get daily-brief running in your business
Tell us what you want to automate. A founder replies within one working day with a plan, not a pitch deck.
Cite this page
daily-brief skill. Agent Mart. https://agentmart.dev/skills/indigoai-us-daily-brief (last updated 2026-10-24)