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/LICENSE +21 -0
- package/README.md +170 -0
- package/SETUP.md +501 -0
- package/dist/audit-4AUZVELT.js +215 -0
- package/dist/chunk-2PLWVW5T.js +987 -0
- package/dist/chunk-6VWWJZKJ.js +27 -0
- package/dist/chunk-EXGTFXNV.js +77 -0
- package/dist/chunk-G4K24I4M.js +425 -0
- package/dist/chunk-NDWZUZJE.js +179 -0
- package/dist/chunk-QKT2FAB5.js +132 -0
- package/dist/chunk-V2UN3JYL.js +140 -0
- package/dist/cli.js +203 -0
- package/dist/init-ZJCI2723.js +122 -0
- package/dist/sample-M7WNKQOV.js +7 -0
- package/dist/seed-7DIDKXT7.js +50 -0
- package/dist/server-B4FWZHS2.js +4814 -0
- package/dist/service-ILBMIZB7.js +240 -0
- package/package.json +66 -0
- package/prompts/README.md +122 -0
- package/prompts/assistant.md +62 -0
- package/prompts/morning-brief-personal.md +442 -0
- package/prompts/morning-brief-work.md +630 -0
- package/public/app.js +5058 -0
- package/public/index.html +36 -0
- package/public/style.css +2515 -0
- package/schema/items.schema.json +99 -0
- package/tools/dfcal/Info.plist +16 -0
- package/tools/dfcal/build.sh +52 -0
- package/tools/dfcal/main.swift +133 -0
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.
|