A minimal, local-first log of what you did and exactly when — to the second.
SecondLog is a single-screen task dashboard. You add a task with its start and end time, and it appears as a row in a calm, dark list you can edit, delete, and export. There is no timer to start, no account to create, and no data leaving your machine.
- Quick capture in the title field — type one line like
wrote spec 9:15-10:40oremail Sam yesterday 14:00-14:20and the date/time fields are filled from it. Add a description in${...}, e.g.wrote spec ${drafted the API section} 9:15-10:40. Addtoday,yesterday, or aYYYY-MM-DDdate; ranges crossing midnight roll over to the next day. Without a time range, the title, description, and date/time fields behave exactly as before. - Log a task — a title, an optional description, and a start and end date + time, precise to the second.
- Read the list — every entry on one page, newest first, with dates and 12-hour times (AM/PM) in tabular monospace.
- Fix mistakes — edit any row inline (or cancel), delete a row.
- Keep it — entries persist in the browser's
localStorageand survive a refresh. - Take it out — export everything as JSON or CSV from the Export menu.
Deliberately not included: no accounts, no projects/tags/clients, no live stopwatch, no charts or reports, no server. A log that stays exact is a log that stays small.
Requires Node.js 20.9 or newer.
npm install npm run dev
Open http://127.0.0.1:3000. The server is bound to the loopback address, so it is reachable from this machine only.
npm run build # production build npm run start # serve the production build npm run lint # eslint
localStorage is per-origin, and http://127.0.0.1:3000 and http://localhost:3000 are different origins — stay on one URL, or the log will look empty on the other. Use Export → JSON to move entries across.
The whole app is one client-rendered page. The interesting logic lives in app/lib/entries.ts:
combineDateAndTime(dateStr, timeStr)turns aYYYY-MM-DDdate plus anHH:MM:SStime into an ISO timestamp, and rejects values that don't round-trip (e.g.2026-02-30).parseQuickEntry(input)pulls a title, an optional${...}description, an optional relative or ISO date, and a clock range (9:15-10:40,9am-9:15am,14:00 to 14:20) out of one line, returning a validated start/end pair. The add form runs it only when the title contains a clock range; otherwiseparseTitleShortcutjust lifts${...}into the description.isValidRange(startIso, endIso)enforces that an entry can't end before it starts — crossing midnight is fine, since the end has its own date.formatTime12(iso)/formatDateShort(iso)render the start and end in the list;dateFromIso(iso)andtimeFromIso(iso)feed the edit form.toCsv(entries)renders the list as CSV, quoting any cell that contains a comma, quote, or newline.
Entries are stored as { id, title, description, startDate, endDate } under the single localStorage key secondlog.entries. page.tsx holds them in React state and writes the full array back to storage on every add, edit, and delete; a read failure is treated as an empty list rather than an error. Nothing is sent anywhere — there is no backend.
The app is local by construction, and that is enforced rather than promised:
- No network at runtime. There is no
fetch,XMLHttpRequest,WebSocket,EventSource, or beacon anywhere inapp/; fonts are self-hosted at build time. - Loopback only. The server binds
127.0.0.1, so it is not reachable from the network. - Your entries never reach the server. They live in
localStorageand are read back by the browser. - No accounts, cookies, analytics, or third-party scripts, and a CSP of
default-src 'self'would block them if one were added. - Security headers (
X-Frame-Options,nosniff,Referrer-Policy,Permissions-Policy, and the CSP) are set innext.config.ts.
SECURITY.md covers the guarantees, what they do not protect against, and how to verify them. docs/ARCHITECTURE.md covers the component map, the data flow, and the trust boundary.
app/
├── layout.tsx # Root layout, fonts, dark theme, metadata
├── page.tsx # The single dashboard: form + list (client component)
├── globals.css # Tailwind base styles
├── lib/entries.ts # Entry type, validation, formatting, CSV, storage helpers
└── components/
├── AddTaskForm.tsx # Title (one-line syntax), description, start/end, "Log task"
├── TaskList.tsx # Rows, inline edit, delete, empty state
├── ExportMenu.tsx # JSON / CSV export
└── icons.tsx # Inline SVG icons
docs/architecture.md # How the app is put together and why it cannot phone home
devpost/ # Planning documents: scope, PRD, spec, build checklist, app map
Built with Next.js (App Router), React, TypeScript, and Tailwind CSS.