daily-focus 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SETUP.md ADDED
@@ -0,0 +1,501 @@
1
+ # Set up Daily Focus
2
+
3
+ [Back to the README](README.md)
4
+
5
+ Daily Focus needs Node.js 22.18 or newer; Node 24 is recommended. The Mac app is
6
+ the exception: it carries its own. GitHub, Jira,
7
+ and the live macOS calendar are optional. The morning brief is written by an agent
8
+ the dashboard runs for you through a coding-agent CLI.
9
+
10
+ ## Start the dashboard
11
+
12
+ ```sh
13
+ npx daily-focus
14
+ ```
15
+
16
+ That starts the dashboard and opens [localhost:4321](http://127.0.0.1:4321) in your
17
+ browser. To keep it running in the background on macOS, install it and run it as a
18
+ service instead:
19
+
20
+ ```sh
21
+ npm install -g daily-focus
22
+ daily-focus service
23
+ ```
24
+
25
+ From a checkout of this repo, `npm install` and then `npm run service` does the same,
26
+ and `npm start` runs it in the terminal. Each `daily-focus <command>` below is
27
+ `npm run <command>` in a checkout, with two differences: `build-calendar` is
28
+ `build:calendar`, and flags go after `--`, as in `npm run audit -- --against <file>`.
29
+
30
+ Until the first brief exists, the Today tab walks you through setting it up:
31
+
32
+ 1. **What it briefs**: your work, or your personal life. See
33
+ [A personal instance](#a-personal-instance) for running both.
34
+ 2. **Your objective**: the one thing you're trying to achieve, which the agent
35
+ ranks the day against.
36
+ 3. **Who writes the brief**: Claude Code or Codex, whichever it finds installed.
37
+ 4. **Where it should look**: your source list, which starts from a template with
38
+ what `gh` and `git` know about you filled in.
39
+ 5. **What else to show**: the pull request board, the Jira board and the live
40
+ agenda, each with its status and a button to turn it off.
41
+ 6. **Write my first brief**, which runs the agent once while you watch.
42
+
43
+ Everything in it stays on the settings page afterwards: the gear in the header, or
44
+ <kbd>,</kbd>. The dashboard keeps its files in `~/.daily-focus/`, and links the
45
+ prompt and schema there each time it starts.
46
+
47
+ `daily-focus service` runs the dashboard in the background on macOS. It starts it
48
+ now, at every login, and again if it crashes, so the dashboard is up when the morning
49
+ agent is due. See [Keep the dashboard running](#keep-the-dashboard-running). On
50
+ another system, or to watch the server in a terminal, run `daily-focus` and keep that
51
+ terminal open while you use the dashboard. `daily-focus --help` lists the rest.
52
+
53
+ If you'd rather write the files by hand, `daily-focus init` creates the store with
54
+ templates for both. It preserves existing files, so you can safely run it again.
55
+
56
+ ## Set your objective and sources
57
+
58
+ Both are on the settings page: **Your objective**, and **Where the agent looks**.
59
+ They are kept as two files in the store, which you can also edit by hand:
60
+
61
+ | File | What to put in it |
62
+ |---|---|
63
+ | `~/.daily-focus/focus.md` | Your current objective, blockers, and context that should guide priorities. |
64
+ | `~/.daily-focus/sources.md` | Your accounts, calendars, and the places your agent should look for updates. |
65
+
66
+ For example, `focus.md` might start with:
67
+
68
+ ```markdown
69
+ ---
70
+ objective: Ship the checkout reliability update
71
+ blocker: Reproduce the staging failure
72
+ ---
73
+ Start with the staging repro before picking up new work.
74
+ ```
75
+
76
+ Leave the objective blank between objectives; the dashboard shows a quiet reminder
77
+ and the agent ranks by urgency alone. To turn the feature off entirely, delete
78
+ `focus.md`.
79
+
80
+ Add `<!-- agent-only -->` on its own line before context you don't want displayed.
81
+ The agent reads that section, and the board never shows it; only the editor on the
82
+ settings page does. The source list is likewise shown only in its editor.
83
+
84
+ The dashboard saves a file only if it hasn't changed since the editor opened it, so
85
+ an edit made by hand meanwhile is never overwritten: the editor says so, and offers
86
+ to load the new version.
87
+
88
+ Keep real names, account handles, and work details in this private store, outside git.
89
+
90
+ ## Connect your morning agent
91
+
92
+ The dashboard runs the agent through a coding-agent CLI you already have. Install
93
+ and log in to the [Codex CLI](https://developers.openai.com/codex/cli) or
94
+ [Claude Code](https://code.claude.com/docs), and choose it in the setup steps or
95
+ under **Morning agent** in the settings. In `.env` or the environment that is:
96
+
97
+ ```dotenv
98
+ DAILY_FOCUS_AGENT=codex
99
+ ```
100
+
101
+ Each scheduled morning at 07:00 local time the dashboard starts the agent through
102
+ that CLI, headless, in the store, and the brief appears when it finishes. Set
103
+ `DAILY_FOCUS_AGENT_AT` to another time, such as `06:30`. The dashboard has to be
104
+ running at the time; if it wasn't, it runs the agent as soon as it is started that
105
+ day, provided nothing has produced a brief for the day yet. It runs once a day,
106
+ whatever became of the run: a failed morning is reported once, not retried every
107
+ half minute. The days are Monday to Friday unless `DAILY_FOCUS_AGENT_DAYS` says
108
+ otherwise; see [Match your working week](#match-your-working-week).
109
+ `DAILY_FOCUS_AGENT_AT=off` means the dashboard never starts a run on its own; the
110
+ refresh icon still does. A new store's first brief always comes from the setup
111
+ steps' button, so the clock never runs the agent before you've told it where to look.
112
+
113
+ Whichever way it starts, every run lands in the same place: the report it gives when
114
+ it finishes, and a chat where you can ask it why it did what it did. See
115
+ [The morning agent's runs](#the-morning-agents-runs).
116
+
117
+ The agent reaches your sources the way the CLI does:
118
+
119
+ - **Codex** runs in its workspace-write sandbox with network access, confined to the
120
+ store. Connectors from the Codex app are found through its plugin catalogue. There
121
+ is nobody to approve a command outside the sandbox, so the agent reports that
122
+ restriction for any `gh` command that needs it, such as switching accounts.
123
+ - **Claude Code** may write `items.json` and nothing else in the store, and reach
124
+ its sources with only what `DAILY_FOCUS_AGENT_TOOLS` allows. The default covers
125
+ GitHub, Jira, web pages and the claude.ai Gmail connector. Add your calendar, chat
126
+ and document connectors to the list by name, or the brief will report them as
127
+ unreachable.
128
+
129
+ Set `DAILY_FOCUS_AGENT_MODEL` and `DAILY_FOCUS_AGENT_EFFORT` if the CLI's own
130
+ defaults are not what you want for a brief; a brief is worth a high effort. If the
131
+ server can't find the CLI, set `DAILY_FOCUS_AGENT_BIN`.
132
+
133
+ The agent writes `items.json`. The dashboard records your actions and focus sessions
134
+ for the next run to read.
135
+
136
+ After the first run, read its report (click "updated … ago"): it says which sources
137
+ it couldn't reach. To check the brief against the payload contract, run:
138
+
139
+ ```sh
140
+ daily-focus audit
141
+ ```
142
+
143
+ The audit checks the brief for duplicate or drifting IDs, missing history, handled
144
+ items raised again, and other contract problems. To compare with a particular brief:
145
+
146
+ ```sh
147
+ daily-focus audit --against /path/to/earlier-items.json
148
+ ```
149
+
150
+ For Google Tasks, this repo includes an optional
151
+ [Apps Script export](apps-script/README.md) that puts a JSON file in Drive for the
152
+ agent to read.
153
+
154
+ ## Configure integrations
155
+
156
+ Settings are saved in the store, in `settings.json`, by the dashboard's settings
157
+ page; saving one restarts the dashboard to apply it once nothing is running. The
158
+ settings below can also go in a `.env` in the repo, which is how they were set
159
+ before the store kept its own:
160
+
161
+ ```sh
162
+ cp .env.example .env
163
+ ```
164
+
165
+ A value saved in the store beats the same one in `.env`, and a variable set in the
166
+ environment the dashboard starts with beats both; the settings page shows such a
167
+ value but can't change it. `.env` is gitignored because account and organisation
168
+ names belong outside git.
169
+
170
+ ### GitHub
171
+
172
+ Sign in with the GitHub CLI:
173
+
174
+ ```sh
175
+ gh auth login
176
+ ```
177
+
178
+ The board uses the active account by default. To choose accounts and repositories,
179
+ set these in `.env`, replacing the invented examples with your own:
180
+
181
+ ```dotenv
182
+ DAILY_FOCUS_GITHUB_ACCOUNTS=alice,alice_corp
183
+ DAILY_FOCUS_GITHUB_SCOPE=acme,acme-labs/webapp
184
+ ```
185
+
186
+ Named accounts stay fixed even if you switch the active account in another terminal.
187
+ For organisations using SAML, make sure the account's token has access. The board
188
+ reports access problems instead of silently showing no pull requests.
189
+
190
+ If your repository has a check that represents its merge policy, list its exact,
191
+ case-sensitive name in `DAILY_FOCUS_GITHUB_MERGE_GATE_CHECKS`. Separate names with
192
+ commas. Pending matches appear under *Waiting on merge gate*.
193
+
194
+ Set `DAILY_FOCUS_GITHUB=off` to disable the board.
195
+
196
+ ### Jira
197
+
198
+ Sign in with the Atlassian CLI:
199
+
200
+ ```sh
201
+ acli jira auth login
202
+ ```
203
+
204
+ The board uses that session. You can limit the projects and adjust which statuses
205
+ need attention:
206
+
207
+ ```dotenv
208
+ DAILY_FOCUS_JIRA_PROJECTS=PROJ,OTHER
209
+ DAILY_FOCUS_JIRA_HOLD_STATUSES=Blocked,On Hold
210
+ DAILY_FOCUS_JIRA_IN_PROGRESS_STATUSES=In Progress
211
+ ```
212
+
213
+ Hold statuses suppress *In flight with nothing linked* reminders. They don't hide
214
+ other status mismatches. The in-progress list filters the *Working on* view;
215
+ without it, that view includes every status Jira puts in its in-progress category,
216
+ which may include In Review.
217
+
218
+ Clicking a status in the dashboard writes one transition to Jira. All other Jira
219
+ access is read-only. See the [ticket board guide](README.md#the-jira-ticket-board)
220
+ for workflow limits and undo behavior.
221
+
222
+ Set `DAILY_FOCUS_JIRA=off` to disable the board.
223
+
224
+ ### Live calendar on macOS
225
+
226
+ The live agenda reads Calendar.app, so meeting changes appear during the day.
227
+ It requires the Xcode command line tools with `swiftc`. Build the helper once; it
228
+ goes in `~/Library/Application Support/Daily Focus/`, where every copy finds it:
229
+
230
+ ```sh
231
+ daily-focus build-calendar
232
+ ```
233
+
234
+ Choose calendar names exactly as Calendar.app shows them, and list your own email
235
+ addresses so the dashboard can recognize meetings you've declined:
236
+
237
+ ```dotenv
238
+ DAILY_FOCUS_CALENDARS=Work,Personal
239
+ DAILY_FOCUS_CALENDAR_ADDRESSES=you@example.com,you@personal.example
240
+ ```
241
+
242
+ Start the dashboard and allow the helper's calendar access when macOS asks.
243
+ Rebuilding the helper may prompt again.
244
+
245
+ Without live calendar access, the agenda uses events from the morning brief.
246
+ Set `DAILY_FOCUS_CALENDAR=off` to use those events explicitly.
247
+
248
+ ## Ask the assistant
249
+
250
+ Every item's panel can have an assistant that runs a coding-agent CLI you already
251
+ have, headless, against that one item. Click the card, pick a quick action or type a
252
+ request, and the answer streams into the panel; you can follow up in the same
253
+ conversation.
254
+ The quick actions cover the common asks: whether a review comment is right, why CI
255
+ is failing, what a thread is asking of you, a reply to an email drafted straight into
256
+ Gmail as a draft on the thread.
257
+
258
+ Install and log in to [Claude Code](https://code.claude.com/docs) or the
259
+ [Codex CLI](https://developers.openai.com/codex/cli), then choose it under
260
+ **Assistant** in the settings, or set:
261
+
262
+ ```dotenv
263
+ DAILY_FOCUS_ASSISTANT=claude
264
+ ```
265
+
266
+ Once the dashboard has restarted, the assistant appears in the panel. Model and effort default to whatever
267
+ the CLI is configured with; `DAILY_FOCUS_ASSISTANT_MODEL` and
268
+ `DAILY_FOCUS_ASSISTANT_EFFORT` override them. If the server can't find the CLI,
269
+ set `DAILY_FOCUS_ASSISTANT_BIN` to its path.
270
+
271
+ The assistant reads and drafts; it never sends, posts or edits anything, and it has
272
+ no checkout to work in. That is deliberate. Fixing merge conflicts or a failing build
273
+ belongs in a real coding session; this panel is for the questions you'd otherwise
274
+ answer by opening six tabs. The Gmail draft is the one thing it creates, through the
275
+ Gmail tool the CLI has: with Claude Code that is the claude.ai Gmail connector, which
276
+ `DAILY_FOCUS_ASSISTANT_TOOLS` allows by default; with Codex it is the Gmail plugin
277
+ from the Codex app, which the CLI finds through its plugin catalogue. Without either,
278
+ the assistant hands you the text instead and says so.
279
+
280
+ Its instructions live in `prompts/assistant.md`, linked into the store as
281
+ `assistant.md` each time the dashboard starts. What it says stays in the chat in the panel: it
282
+ never leaves notes on the item or marks it handled. That is yours to do once you have
283
+ read the reply.
284
+
285
+ ## The morning agent's runs
286
+
287
+ Every run the dashboard starts, on its clock or by hand, is recorded in the store.
288
+ The refresh icon beside "updated … ago" on the Today tab starts one now, for the
289
+ day that has moved on from the morning's brief. It rewrites the brief from scratch;
290
+ what you have marked done, snoozed or noted is kept, and the brief it replaces is
291
+ in the archive. While it runs, a banner says so and offers Stop; click the banner
292
+ to watch the run. When it finishes the banner goes, since the brief it wrote is the
293
+ page. A run that fails stays as a warning until you dismiss it.
294
+
295
+ Click "updated … ago" to open the latest run in the panel. It holds the agent's
296
+ report — what it wrote, what it dropped as handled, and any source it could not
297
+ reach — with everything it said on the way there folded away beneath, and a field
298
+ to ask it about the run. The question goes to the agent in the
299
+ same session, so it answers from what it actually did: why it dropped an item, what
300
+ it could not find, whether it can find it now. A follow-up is given nothing to
301
+ write; if something in the brief should change, it says what, and you run it again.
302
+ Earlier runs are folded away at the foot of the panel, newest first, and any of
303
+ them opens the same way.
304
+
305
+ The dashboard runs one thing at a time: a run, or a question about one.
306
+
307
+ ## Keep the dashboard running
308
+
309
+ There are two ways on macOS: the menu bar app, or a LaunchAgent. Use one, not both;
310
+ the app notices a dashboard that is already running and only watches it.
311
+
312
+ ### The menu bar app
313
+
314
+ Daily Focus as a Mac app lives in the menu bar. It starts the dashboard, again if it
315
+ stops, and at login once you tick **Open at Login**. Its menu says how old the brief
316
+ is and how many items are open, opens the dashboard or its settings, and starts a
317
+ fresh brief; it posts a notification when a new brief arrives or the morning agent
318
+ fails. It carries everything it runs: its own copy of the dashboard, the Node.js
319
+ that runs it, and the calendar helper, so there is nothing else to install, and the
320
+ calendar permission is asked for once, by an app you recognise. It needs a Mac with
321
+ Apple silicon and macOS 13.5 or newer.
322
+
323
+ Open `Daily Focus.dmg` and drag the app to Applications, then open it from there.
324
+ It has no window and no Dock icon: look for it in the menu bar.
325
+
326
+ To build it yourself from a checkout:
327
+
328
+ ```sh
329
+ npm run app
330
+ ```
331
+
332
+ That leaves `Daily Focus.dmg` and the app itself in `macos/build/`. Its log is
333
+ `~/Library/Logs/Daily Focus.log`. Everything the dashboard starts runs inside the
334
+ app as far as macOS is concerned, so a permission prompt from the morning agent's
335
+ CLI, for Reminders, Messages or your calendars, names Daily Focus, and Full Disk
336
+ Access, if a source needs it, is granted to the app.
337
+
338
+ ### A LaunchAgent
339
+
340
+ On macOS, `daily-focus service` installs a LaunchAgent for your user that runs this
341
+ copy of the dashboard: the global install, or the checkout it was run from. It
342
+ starts at login and again after a crash. If you stop the
343
+ dashboard yourself, it stays stopped until the next login. The command waits until
344
+ the dashboard answers and prints its address, or prints the end of its log if it
345
+ doesn't.
346
+
347
+ Run `daily-focus service` again to restart it after updating (`npm install -g
348
+ daily-focus`), pulling changes into a checkout, or switching Node versions. From a
349
+ checkout it rebuilds the page each time the dashboard starts. It won't install from
350
+ `npx`, whose copy npm replaces with the next version: install it globally first.
351
+
352
+ The LaunchAgent is written for this machine and isn't tracked in git, so each
353
+ machine runs the command once. It uses the Node.js that ran it and keeps two things
354
+ from your shell: `PATH`, so the dashboard finds `gh`, `acli` and your agent's CLI,
355
+ and any `DAILY_FOCUS_` variables set there. Each time it starts, the dashboard also
356
+ asks your login shell for its `PATH`, so a CLI installed since is found without
357
+ reinstalling the service. Everything else comes from the store's settings and
358
+ `.env`, which are read each time the dashboard starts. A CLI that relies on a token
359
+ exported in your shell profile, rather than its own login, won't find it.
360
+
361
+ Each store gets one service. Running the command again for the same store replaces
362
+ the service, and another store gets a service of its own. It refuses to install if
363
+ something already has the port, such as a dashboard you started in a terminal;
364
+ stop that one first.
365
+
366
+ The dashboard's output goes to `~/Library/Logs/local.daily-focus.log`, or a log
367
+ named after the store if you use another one. To stop the service and uninstall it:
368
+
369
+ ```sh
370
+ daily-focus service --remove
371
+ ```
372
+
373
+ ## A personal instance
374
+
375
+ Daily Focus can brief your personal life as well as your work: email, family
376
+ calendars, Apple Reminders, Apple Messages, e-Boks and your own GitHub projects. Run it as a second instance
377
+ with its own store, server and morning agent, and choose **Personal life** in its
378
+ setup steps, or set:
379
+
380
+ ```dotenv
381
+ DAILY_FOCUS_PROFILE=personal
382
+ ```
383
+
384
+ The dashboard then links the personal prompt, `prompts/morning-brief-personal.md`,
385
+ into the store as `prompt.md`, and the source list starts from a template with
386
+ sections for those sources. The profile also switches off
387
+ the Jira board and away detection, and gives the tab a green house icon instead of the blue briefcase. The pull request
388
+ board stays on for side projects; point it at your personal account with
389
+ `DAILY_FOCUS_GITHUB_ACCOUNTS`, or set `DAILY_FOCUS_GITHUB=off`.
390
+
391
+ The personal sources often live on another machine, such as a home Mac with access
392
+ to Messages and Reminders. Run the instance there, keep `DAILY_FOCUS_HOST` on
393
+ loopback, and share it with your other devices through
394
+ [Tailscale Serve](https://tailscale.com/kb/1312/serve):
395
+
396
+ ```sh
397
+ tailscale serve --bg http://127.0.0.1:4321
398
+ ```
399
+
400
+ Only your tailnet can reach it, over HTTPS. Don't bind the server to your LAN
401
+ instead: it has no login, and a personal brief holds your mail and messages.
402
+
403
+ The dashboard answers only when it is reached as localhost, by IP address, by a
404
+ Tailscale `ts.net` name, or by the name in `DAILY_FOCUS_HOST`. That stops a web page
405
+ from pointing its own name at your dashboard and reading your brief. Reached any
406
+ other way, it replies `403` and names the host it was reached as.
407
+
408
+ To run both instances on one machine, start the second with its own
409
+ `DAILY_FOCUS_DATA`, `DAILY_FOCUS_PORT` and `DAILY_FOCUS_PROFILE` in its environment,
410
+ which takes precedence over `.env`. `daily-focus service` keeps those variables, so this
411
+ installs the second service beside the first. Use the same variables each time you
412
+ run it for that instance:
413
+
414
+ ```sh
415
+ DAILY_FOCUS_PROFILE=personal DAILY_FOCUS_DATA=~/.daily-focus-personal DAILY_FOCUS_PORT=4322 daily-focus service
416
+ ```
417
+
418
+ ## Match your working week
419
+
420
+ Set `DAILY_FOCUS_AGENT_DAYS` to the days the dashboard runs the agent. It uses cron
421
+ weekday numbers: `1-5` for Monday to Friday, `0-4` for Sunday to Thursday, or `0,6`
422
+ for weekends. Unset means Monday to Friday. `daily-focus audit` shows the schedule in
423
+ use. Days without scheduled runs don't make a brief overdue. Once a refresh is due,
424
+ the dashboard allows 45 minutes before showing a warning.
425
+
426
+ ## Settings reference
427
+
428
+ All settings can be changed on the settings page, which saves them in the store,
429
+ or set in `.env` or the environment; restart after changing those two by hand.
430
+ `DAILY_FOCUS_DATA`, `DAILY_FOCUS_PORT` and `DAILY_FOCUS_HOST` say where the store is
431
+ and how the dashboard listens, so they are never kept in the store and only the
432
+ environment or `.env` can change them. Their defaults suit almost everyone.
433
+ The brief's `dayStart` and `dayEnd` override the configured working hours. Neither
434
+ matters when `DAILY_FOCUS_FREE_WINDOWS` is off.
435
+
436
+ | Variable | Default | Purpose |
437
+ |---|---|---|
438
+ | `DAILY_FOCUS_PROFILE` | `work` | `work` or `personal`. Picks the prompt the dashboard links and the defaults marked below |
439
+ | `DAILY_FOCUS_DATA` | `~/.daily-focus` | Where the store lives |
440
+ | `DAILY_FOCUS_PORT` | `4321` | Port for the dashboard |
441
+ | `DAILY_FOCUS_HOST` | `127.0.0.1` | Loopback only by default, since this is personal data. A name here is also one the dashboard answers to, besides localhost, IP addresses and `ts.net` names |
442
+ | `DAILY_FOCUS_FREE_WINDOWS` | `on`; `off` for personal | `off` shows events only: no free windows in the agenda, and the next event in place of focus time left |
443
+ | `DAILY_FOCUS_WORK_START` | `9` | Local hour the working day starts, when the brief doesn't say |
444
+ | `DAILY_FOCUS_WORK_END` | `17` | Local hour the working day ends when the brief does not specify it |
445
+ | `DAILY_FOCUS_MIN_FREE_WINDOW` | `45` | Minutes before a gap counts as a focus window |
446
+ | `DAILY_FOCUS_STALE_AFTER_HOURS` | `24` | When to expect a refresh. Shows an informational message for 45 minutes before warning that the agent may not have run. Counted only in hours a run was due, so days off never trip it |
447
+ | `DAILY_FOCUS_AGENT_DAYS` | `1-5` | Weekdays the dashboard runs the agent on, cron-style and cron-numbered: `1-5` for Monday to Friday, `0-4` for Sunday to Thursday, `0,6` for a weekend-only run |
448
+ | `DAILY_FOCUS_SESSION_MINUTES` | `25` | Default focus session length |
449
+ | `DAILY_FOCUS_AWAY_AFTER` | `10`; `0` for personal | Minutes of an untouched machine before a session is closed at the last sign of life. `0` turns it off |
450
+ | `DAILY_FOCUS_GITHUB` | `on` | `off` disables the pull request board; nothing is polled |
451
+ | `DAILY_FOCUS_GITHUB_ACCOUNTS` | *gh's active account* | Logins to poll as, comma-separated, each resolved with `gh auth token --user` |
452
+ | `DAILY_FOCUS_GITHUB_SCOPE` | *everything* | Organisations or `owner/repo` entries to limit the board to, comma-separated |
453
+ | `DAILY_FOCUS_GITHUB_MERGE_GATE_CHECKS` | *none* | Check names that stand for a repository's whole merge policy, comma-separated and matched exactly. Their rows get the *Waiting on merge gate* bucket |
454
+ | `DAILY_FOCUS_GITHUB_POLL_MINUTES` | `5` | Minutes between polls while a tab is open |
455
+ | `DAILY_FOCUS_GH` | `gh` | Path to the GitHub CLI, for when the server's PATH lacks it. `~` is expanded |
456
+ | `DAILY_FOCUS_CALENDAR` | `on` | `off` disables the live agenda; the brief's own events are used instead |
457
+ | `DAILY_FOCUS_CALENDARS` | *none* | Calendar names to show, comma-separated and spelled as Calendar.app spells them. Empty means nothing is read |
458
+ | `DAILY_FOCUS_CALENDAR_ADDRESSES` | *none* | Your own email addresses, comma-separated, used to find your reply among an event's attendees |
459
+ | `DAILY_FOCUS_CALENDAR_POLL_MINUTES` | `5` | Minutes between calendar reads while a tab is open |
460
+ | `DAILY_FOCUS_CALENDAR_APP` | *built copy* | Path to the calendar helper bundle, if it isn't the one `daily-focus build-calendar` installs |
461
+ | `DAILY_FOCUS_JIRA` | `on`; `off` for personal | `off` disables the Jira ticket board; nothing is read |
462
+ | `DAILY_FOCUS_JIRA_PROJECTS` | *everything* | Project keys to limit the search to, comma-separated |
463
+ | `DAILY_FOCUS_JIRA_HOLD_STATUSES` | *none* | Statuses where standing still is deliberate, comma-separated and spelled as your Jira spells them. Their rows are exempt from *In flight with nothing linked*, and from nothing else |
464
+ | `DAILY_FOCUS_JIRA_IN_PROGRESS_STATUSES` | *all of them* | The statuses the ticket board's *Working on* view shows, comma-separated and case-insensitive. Use `In Progress` to leave out In Review |
465
+ | `DAILY_FOCUS_JIRA_POLL_MINUTES` | `15` | Minutes between reads while a tab is open |
466
+ | `DAILY_FOCUS_JIRA_SITE` | *acli's own* | Atlassian site host the browse links are built from. A pasted URL is fine |
467
+ | `DAILY_FOCUS_ACLI` | `acli` | Path to the Atlassian CLI, for when the server's PATH lacks it. `~` is expanded |
468
+ | `DAILY_FOCUS_ASSISTANT` | `off` | `claude` or `codex` puts an assistant in every item's panel that runs that CLI headless against the item. `off` hides it |
469
+ | `DAILY_FOCUS_ASSISTANT_BIN` | *the CLI's name* | Path to the assistant's CLI, for when the server's PATH lacks it. `~` is expanded |
470
+ | `DAILY_FOCUS_ASSISTANT_MODEL` | *the CLI's own* | Model passed to the CLI untouched: an alias like `opus`, or a full id. Unset passes no flag |
471
+ | `DAILY_FOCUS_ASSISTANT_EFFORT` | *the CLI's own* | Effort passed to the CLI untouched: `low`, `medium`, `high`, `xhigh` or `max`. Unset passes no flag |
472
+ | `DAILY_FOCUS_ASSISTANT_TOOLS` | `Bash(gh *),Bash(acli *),WebFetch,mcp__claude_ai_Gmail` | What Claude Code may use without asking, in its permission syntax, comma-separated. Editing tools are denied regardless. Ignored by Codex |
473
+ | `DAILY_FOCUS_AGENT` | `off` | `codex` or `claude` lets the dashboard run the morning agent through that CLI: each scheduled morning, and from the refresh icon beside the brief's age. `off` hides it |
474
+ | `DAILY_FOCUS_AGENT_AT` | `07:00` | Local time, `HH:MM`, at which the dashboard starts the agent on each scheduled day, or as soon as it is running after that. `off` means it never starts one on its own; the refresh icon still does. Needs `DAILY_FOCUS_AGENT` |
475
+ | `DAILY_FOCUS_AGENT_BIN` | *the CLI's name* | Path to that CLI, for when the server's PATH lacks it. `~` is expanded |
476
+ | `DAILY_FOCUS_AGENT_MODEL` | *the CLI's own* | Model passed to the CLI untouched. Unset passes no flag |
477
+ | `DAILY_FOCUS_AGENT_EFFORT` | *the CLI's own* | Effort passed to the CLI untouched. Unset passes no flag |
478
+ | `DAILY_FOCUS_AGENT_TOOLS` | `Bash(gh *),Bash(acli *),WebFetch,mcp__claude_ai_Gmail` | What Claude Code may use to reach your sources, in its permission syntax, comma-separated. Writing `items.json`, and nothing else in the store, is allowed regardless. Ignored by Codex |
479
+
480
+ ## If something looks wrong
481
+
482
+ - If the dashboard is gone after a restart, it was probably started in a terminal,
483
+ which it ends with. Run `daily-focus service` to keep it running. If the
484
+ service is installed and the page still doesn't load, read
485
+ `~/Library/Logs/local.daily-focus.log`.
486
+ - Before the first brief, the Today tab shows the setup steps. Once a brief has
487
+ existed, an empty Today tab means the agent hasn't written a new `items.json`:
488
+ start a run from the refresh icon beside the brief's age.
489
+ - A stale brief needs an agent run. Refreshing a board doesn't regenerate the brief;
490
+ the icon beside the brief's age does. Click "updated … ago" to see what the last
491
+ run said, or whether there was one: the dashboard has to be running at
492
+ `DAILY_FOCUS_AGENT_AT`, 07:00 by default, or started later that day.
493
+ - A GitHub or Jira warning may mean the CLI session needs authentication. If the
494
+ server can't find a CLI, set its full path with `DAILY_FOCUS_GH` or `DAILY_FOCUS_ACLI`.
495
+ - The boards keep their last successful results during an outage. Check the status
496
+ line for the age of the data.
497
+ - If port 4321 is already in use, set `DAILY_FOCUS_PORT` to another port.
498
+
499
+ `daily-focus seed` refuses to replace an existing brief and prints the path it found.
500
+ Use the [temporary demo](README.md#try-it) for sample data, never your real store.
501
+ `daily-focus seed --force` overwrites the brief anyway.