Repository navigation
A pass must be able to label its own source #94
Description
Question
runOrganizePass() hardcodes source: "manual" in its history write, so a pass launched by cron reports itself as manual. Nothing in src/ can produce the string scheduled, even though the type, both history query filters, and the view_history markdown output all already accept and display it.
The defect, exactly:
src/extensions/scheduler/organize-pass.ts:113writessource: "manual"as a literal.src/server.ts:167writessource: "manual"for every MCP tool call. Correct today, since a tool call is manual by definition.HistoryEntry.sourceis"manual" | "scheduled"(src/services/history-logger.service.ts:23).SearchHistoryInputSchema.sourceaccepts both (src/schemas/system.ts:115).ViewHistoryInputSchema.sourceaccepts both (src/schemas/system.ts:58).
So the value is declared, filterable, and displayable, and unreachable.
Consequence. Every consumer that wants "what did my schedule do" gets nothing.
- #49 organizer_digest filtering on
source: "scheduled"matches nothing. - #31 watch_status cannot tell a scheduled pass from an agent's
organize_files. view_historywithsource: "scheduled"returns an empty list on a system used purely on a timer, which is a silent wrong answer rather than an error.
Decision already taken during charting, this ticket records the implementation. A process cannot detect that cron started it. The caller knows, so the caller says. Add a --source flag to once, defaulting to manual, and thread it into runOrganizePass.
Implementation detail.
src/extensions/scheduler/watch.schemas.tsholds the existing flag schemas for the watch CLI. Add the source flag there rather than parsing by hand inonce-cli.ts.parseOnceFlags(src/extensions/scheduler/once-cli.ts:57) rejects unknown-prefixed flags. Add--source manual|scheduledto the known set there.- Add
source?: "manual" | "scheduled"toOrganizePassOptions(organize-pass.ts:21), defaulting to"manual"so every existing caller is unchanged. - Replace the literal at
organize-pass.ts:113with the resolved value. - Document the crontab line in whatever doc tells users how to schedule a pass. The crontab is the thing that knows, so the flag belongs there. Example shape:
*/15 * * * * file-organizer-watch once --apply --source scheduled ~/Downloads.
Do not add a third enum value. That is ruled out, see the map's Out of scope.
Tests that must fail without this change.
organize-pass.tswithsource: "scheduled"produces a history row whosesourceisscheduled. Assert on the row, not on a spy.once-cli.tsrejects--source bogusas a usage error, matching how it treats other unknown flags.once --source scheduled --dry-runwrites no row at all, since the dry-run early return atorganize-pass.ts:106must stay before the history write.
Proof. node .opencode/skills/verify-file-organizer/scripts/control-file-organizer.mjs in a sandbox, reading back operations.jsonl after driving once --apply --source scheduled.
Blocks. organizer_digest and file_organizer_watch_status both need a truthful source to filter on.
Activity
kridaydave commentedon Oct 9, 2026
Resolution
Landed in #88, commit
a1178c8("add --source flag to the once command so cron passes can label their history rows"). The branch also carried the EXIF calendar fix; kriday chose to merge the two together, and the PR body documents both.The decision. A process cannot detect that cron started it, so the caller says.
--sourceon theoncecommand is how a crontab line asserts it. No third enum value: the flag takes the same two valuesHistoryEntry.sourcealready had.Implementation.
OnceSourceSchemainsrc/extensions/scheduler/watch.schemas.ts, az.enum(["manual", "scheduled"]). This is the one place the assertion is checked, so the CLI andOrganizePassOptionsread the same type.parseOnceFlagsinonce-cli.tsiterates by index now, so--sourcecan consume the argument after it. Afor...ofwould have read that value as a second directory and rejected a good command line.OrganizePassOptions.source, optional, defaults to"manual", so every existing caller is unchanged.runOrganizePasswrites the resolved value where it used to write the literal.Tests, in
tests/integration/once-single-pass.test.ts: the scheduled row, the manual default, no row at all for a scheduled dry run, and--source bogusplus--sourcewith no value as usage errors.Proof on the real server, sandbox config under
XDG_CONFIG_HOME, data undertests/sandbox/(gitignored, removed after):--source scheduled: exit 0,historyLogged: false, no row inoperations.jsonl--apply --source scheduled: exit 2, row{"source":"scheduled","status":"success","filesProcessed":2}{"source":"manual","filesProcessed":0}--apply --source bogus: usage error, exit 1, no pass runfile_organizer_search_historywithsource: "scheduled"driven over stdio on the real server: 1 of 1 entries returned, the scheduled one. That filter is what organizer_digest #49 and file_organizer_watch_status #31 needed, and it now matches something.The gap this ticket describes as unreachable is closed:
scheduledis producible, filterable, and displayed.