Focus Forensics
SkillDev toolsWeekly attention forensics from Littlebird capture. Trigger on how fragmented was my week, where did my attention go, focus report, am I context switching too much, what broke up my week, rabbit hole check, weekly focus review, why did I get nothing done. Counts observed switches between work contexts, run length in consecutive snapshots, fragmentation by hour of day, named rabbit holes against stated intentions, and meeting load against unbroken calendar time. Ships week-over-week change plus one behavioral experiment to try. Never produces hours lost, percentages of the day, or a productivity score, because periodic snapshots cannot measure those. Self-analysis only, never pointed at another person.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Focus Forensics skill
What this skill tells your AI
The instructions your AI receives, as published by legioncodeinc/vibe-coding-tools in src/quarantine/skills/keep/focus-forensics/SKILL.md and read by ahel’s review.
Shows the user the structure of their own week: where work held together, where it broke apart, which hours were most broken up, what kept reappearing next to something they said they were not doing, and how all of that changed since last week.
It does not tell them how many hours they lost, because it cannot know that and neither can anything else built on periodic screen capture.
Purpose
Littlebird takes periodic snapshots of the screen. It is not a continuous time tracker. Between any two snapshots nothing is observed: not whether the user was at the machine, not whether the visible window was the focused one, not what happened in the gap.
That single fact determines the whole design. A skill built on this instrument can count transitions, measure runs in consecutive snapshots, compare hour against hour within one person, name recurring topics, do arithmetic on a real calendar, and compare this week to last week. It cannot produce a time ledger, and a report that says "you lost 6 hours to context switching" is asserting something the instrument never measured.
The evidence is not marginal on this point. Even full continuous OS-level window logging
across 1,509 hours could not establish "how engaged a user was with a window in active
use" without interrupting participants to ask
(references/research/distilled-attention-fragmentation.md, section 6). The controlled
experiment most often cited for the hours framing found interrupted participants finishing
FASTER, at 20.31 and 20.60 minutes against 22.77 uninterrupted, with the cost appearing in
stress and frustration rather than in elapsed time
(references/research/distilled-attention-fragmentation.md, section 2). And the famous
"23 minutes 15 seconds to refocus" figure appears in interviews and media, not in any
paper; this sweep fetched the full text of the study usually credited with it and verified
that the number 23 does not appear anywhere in it
(references/research/distilled-attention-fragmentation.md, section 1).
So the skill ships switching patterns and fragmentation structure. Read
references/what-snapshots-can-and-cannot-measure.md before writing any number into any
output. It carries the forbidden-claims list and it is not advisory.
Littlebird MCP calls used
Real tool names, verified in references/littlebird-mcp-reference.md.
| Tool | Used for |
|---|---|
search_user_context | The daily snapshot backbone with filters.data_source: "snapshots", the compressed pass with "summaries", stated intentions with search_queries_messages, and per-app presence checks with filters.app |
LB_INTERNAL_LIST_MEETINGS | Meeting load and unbroken calendar time, over the window and again with a future end_date for the week ahead. The one genuinely measured input this skill has |
LB_INTERNAL_GET_MEETING | The ## For You and ## Action Items blocks, as a source of stated intentions with owner attribution |
LB_INTERNAL_GET_ROUTINE_REPORTS | Reading this skill's own past reports before computing week-over-week change. Mandatory on every run |
LB_INTERNAL_CREATE_ROUTINE | Offering to set up the weekly observer, after approval |
LB_INTERNAL_GET_ROUTINE_CONFIG and LB_INTERNAL_UPDATE_ROUTINE | Editing an existing routine. GET_CONFIG first, always: prompt and schedule are replaced wholesale |
LB_INTERNAL_GET_SUBSCRIPTION_STATUS | Checking the plan supports another routine before offering to create one |
Not used, and worth naming so nobody reaches for them: there is no Littlebird tool that
searches past Littlebird chat conversations, so stated intentions come from
search_user_context with search_queries_messages and from meeting summary blocks. There
is no calendar tool; upcoming events come from LB_INTERNAL_LIST_MEETINGS with a future
end_date. Meeting transcripts are not fetched by this skill at all.
Capability gate
This skill requires the Littlebird MCP on a Power or Pro plan.
Before anything else:
- List the tools actually available in this session and use the real tool names. Do not
assume a tool exists because it is named in
references/littlebird-mcp-reference.md. - If no Littlebird MCP tools are present, stop and tell the user the skill needs the Littlebird MCP connected. Do not attempt a partial run from memory or from any other source.
- If routine creation is part of the request, call
LB_INTERNAL_GET_SUBSCRIPTION_STATUSfirst to confirm the plan supports another routine.
Read references/evidence-standards.md before writing any output. Every line in the report
is observed, inferred, external or unknown, and the kind is visible to the reader.
Trigger
Direct asks: how fragmented was my week, where did my attention go, focus report, am I context switching too much, what broke up my week, rabbit hole check, weekly focus review, why did I get nothing done this week, which hours are my best.
Indirect triggers worth catching: the user says the week felt scattered, asks what happened to a specific day, asks whether a change they made last week helped, or asks to see whether their calendar is eating their mornings.
Do NOT trigger on a request to analyze anyone else's activity. See the guardrail.
Routine cadence
| Mode | Trigger | Window | Output |
|---|---|---|---|
| Weekly routine | Scheduled, unattended, Monday morning | Last 7 days, plus its own past reports | A routine report naming this week's structure and what CHANGED. No files, no approvals |
| On demand | User asks in Cowork or Claude Code | 7 days by default, 14 or 28 on request | The full report file, plus the context taxonomy confirmation on a first run |
The routine observes and reports. The on-demand run writes the file, confirms the taxonomy,
and holds the rabbit hole confirmation gate open. A routine cannot create or update routines
and cannot hold an approval gate open
(references/littlebird-mcp-reference.md).
Offer to create the routine. Routines CAN be created from an interactive session. Show
the user the exact prompt text and schedule from the routine wiring section below, get
approval with AskUserQuestion, then call LB_INTERNAL_CREATE_ROUTINE. Do not tell the
user to go and set it up by hand.
Process
0. Read the past reports first
Call LB_INTERNAL_GET_ROUTINE_REPORTS on the focus-forensics routine with limit 8 before
any retrieval, and extract the fields listed in
references/week-over-week-reporting.md. Week-over-week change is this skill's primary
output, and it cannot be computed from a window read in isolation.
If no routine exists and no prior artifact is present in the working directory, this is a first run. Say so, produce the single-window report, and offer the routine.
1. Retrieve
Full brief in references/switch-and-run-detection.md, step 1. Day-scoped parallel calls
for the snapshot backbone, one compressed summaries pass, one intentions pass, targeted
per-app presence checks, and the meeting list over the window and one week forward.
Narrow parallel queries beat one broad query on both scoring and result size; a broad query
returns 70,000 plus characters and gets dumped to a file
(references/littlebird-mcp-reference.md). Read the relevance scores: items below 3 are
omitted by the server entirely and a 3-scored item never establishes a context run on its
own.
2. Deduplicate, order, label
references/switch-and-run-detection.md, steps 2 and 3. Collapse OCR duplicates, sort by
timestamp because retrieval returns items by relevance rather than chronologically
(references/evidence-standards.md, rule 8), then assign each snapshot a work context.
The context taxonomy rule that matters most: the same app can carry several contexts.
Collapsing a browser to one context destroys the entire analysis, because a browser-heavy
user would then show almost no switching. Where OCR does not support a confident label the
context is unclear, and the count of unclear snapshots is reported next to every metric
that depends on labeling.
Context labels are inferences layered over observations and the report says so
(references/evidence-standards.md, rule 2).
3. Compute the structure
Run scripts/switch_metrics.py on the labeled snapshot list. It derives the observed
cadence and the gap threshold, classifies every adjacent pair as a switch, hold, break or
unclear boundary, builds the run distribution, computes hour and weekday transition rates
with their sample sizes and a reporting floor, finds bursts, and emits an exclusions block.
The arithmetic is deterministic and a wrong headline count is the fastest way this report loses trust, which is why it lives in a script rather than in the model's head. The script assigns no labels and makes no judgments; every one of those stays with the model and the user.
Full definitions in references/switch-and-run-detection.md, steps 4 through 9: what
counts as a switch, why a break is never a switch and never interpreted, how runs are built
and reported as a distribution rather than a mean, the hour-bucket floor, meeting load
arithmetic, and what a burst is.
4. Name rabbit holes, if any clear the bar
references/rabbit-hole-identification.md. Three conditions, all required: three or more
separate runs, inside a window where the user stated a different intention in their own
captured words, and not plausibly part of that intention.
No stated intention means no rabbit hole finding. Without one the skill would be substituting its own opinion about what the user should have been doing, which is exactly the register that gets a report turned off.
Every named rabbit hole carries the quoted intention with its receipt, the run count and snapshot count, the dates and times of each run, and a neutral description. Missing any of the four, it does not appear. Cap the section at two.
The attribution guardrail applies at full strength: captured content shows what the user
was VIEWING, not what they wrote (references/evidence-standards.md, rule 4). An intention
that cannot be attributed to the user is not an intention.
5. Compare against last week
references/week-over-week-reporting.md. Run the four comparability gates before printing
a single delta: cadence, coverage, taxonomy overlap, and unclear rate. A gate that fails is
reported, not worked around.
Then compare the metrics listed in that guide, respect the indifference band, and do not call two points a trend.
This is the section that goes above the fold. Two measurements taken by the SAME imperfect
method can be compared, because whatever the method distorts it distorts both times, and
that is far more defensible than either week's absolute number
(references/research/distilled-attention-fragmentation.md, section 4).
6. Offer one experiment
One change, tied to the specific pattern observed, with a way to tell next week whether it
worked. Selection table, the four required parts, and the two forbidden nudges are in
references/week-over-week-reporting.md.
The two forbidden nudges, restated here because they will otherwise be offered every week:
never present batching email as a proven remedy, because the only logged test of it found
no stress benefit
(references/research/distilled-attention-fragmentation.md, section 9); and never suggest
the user try harder or be more disciplined, because the interventions that moved measured
behavior removed something from the environment while the one that asked the person to
reorganize around the same environment failed
(references/research/distilled-attention-fragmentation.md, section 9).
7. Write it in the right register
references/week-over-week-reporting.md, tone section. Neutral and curious. A colleague
showing the user something interesting in the data, not a coach and not an auditor.
A report that makes the user feel judged gets turned off in two weeks, and a skill that is
turned off has zero effect regardless of accuracy. The banned word list is in that guide
and half of it is banned for being false rather than for being unkind: the instrument
cannot measure distracted, productive, deep work or flow state, so those words are
not available even when they would be flattering.
Retrieval brief
The actual calls. Substitute the window dates. Per-family detail in
references/switch-and-run-detection.md.
The daily snapshot backbone, run once per day in the window, never once for the window
search_user_context
search_queries: ["what was on screen", "application in use", "document being edited",
"browser tab", "terminal or editor"]
standalone_query: a one sentence statement that this is a sweep of everything captured
on this one day, in order, to reconstruct which contexts appeared
date_range: {start: "YYYY-MM-DD 00:00:00", end: "YYYY-MM-DD 23:59:59"}
filters: {data_source: "snapshots"}
The compressed pass, to name contexts and catch days the backbone thinned out
search_user_context
search_queries: ["what I worked on", "activity summary"]
date_range: {start: window start, end: "now"}
filters: {data_source: "summaries"}
Summaries name contexts and fill gaps. They are never counted as snapshots. Mixing the two units corrupts every count in the report.
Stated intentions, which rabbit-hole detection requires
search_user_context
search_queries: ["today I need to", "priority for this week", "focus on",
"plan for today", "to do list"]
search_queries_messages: ["what I said I would work on", "I am working on"]
date_range: {start: window start, end: "now"}
Only messages tagged (From:[user]) are the user's own
(references/evidence-standards.md, rule 4). Message items carry a send time that differs
from the collection time, and the send time governs the timeline
(references/evidence-standards.md, rule 8).
Per-app presence checks, only for apps a first pass already surfaced
search_user_context
search_queries: [the app or site name, the app name plus a typical task in it]
date_range: {start: window start, end: "now"}
filters: {app: "the app", data_source: "snapshots"}
Meetings and unbroken calendar time
LB_INTERNAL_LIST_MEETINGS
start_date: window start
end_date: window end
limit: 100
Run again with end_date one week in the future for the shape of the week ahead. Upcoming
events carry no id, no summary and no transcript
(references/littlebird-mcp-reference.md). Unrecorded calendar events count exactly as
much as recorded ones here: the block was on the calendar either way.
Intentions from meetings, for meetings that produced them
LB_INTERNAL_GET_MEETING
meeting_id: the recorded ids from the list above
Take the ## For You section and the ## Action Items lines owned by the user. Both carry
owner attribution already (references/littlebird-mcp-reference.md). Do not fetch
transcripts; this skill has no use for them.
Empty retrieval
If snapshot retrieval returns nothing across the window, report the window, the queries
run, and the date ranges tried, and stop (references/evidence-standards.md, rule 9). Do
not widen the window silently, do not substitute a plausible week, do not reason from what
the user was probably doing.
If retrieval returns snapshots for fewer than three days in a seven day window, or fewer than 50 snapshots total, coverage is too thin for the switching analysis. Report the coverage that existed, deliver the meeting-load section on its own since calendar data is unaffected, skip the week-over-week comparison, and skip the nudge. A nudge from a thin week is a guess dressed as a finding.
If the meeting list is empty but snapshots are present, run everything else and say the calendar section had no entries. That is a real finding about the week, not a failure.
Output
One file per deep run:
focus-forensics-YYYY-MM-DD.md
in the working directory or a directory the user names, dated by the window END date.
Ten sections, in fixed order with fixed headings so a later run can parse its own prior
output. Full spec in references/week-over-week-reporting.md.
## How this was measured. The limitation note verbatim, window dates, observed cadence, queries run.## Coverage. Days with snapshots, snapshot count, per-day counts, break count,unclearshare, any failed comparability gate.## This week's structure. Snapshot count, switch count, transition rate, median run length in snapshots, longest run with its bounded interval, count of runs of length 1, count of runs of length 5 or more, burst list.## Compared with last week. The comparison table. The primary section.## By hour and by day. Top three and bottom three hours with sample sizes, weekday shape, thin hours listed separately.## Meetings and unbroken calendar time. Meeting count, scheduled minutes, gaps of 90 minutes or more. Real minutes, no causal claim.## Recurring alongside a stated intention. At most two rabbit holes, or a line saying none cleared the bar.## Last week's experiment. Passed, failed, or inconclusive, with both numbers.## One thing to try this week. The nudge, in four parts.## What this report did not look at. Excluded categories, the forbidden claims, any named gap that affected this run.
The context taxonomy persists across runs in focus-contexts.md in the same directory, so
that week two counts the same things week one counted.
Raw retrieved capture is working data and does not ship in the artifact
(references/evidence-standards.md, rule 7).
Nothing is sent, posted, or written into any third-party system. This is a private
artifact for the user alone. If the user asks for a shareable version, show them the exact
text and get approval of the words rather than of the plan
(references/evidence-standards.md, rule 6). Approving a plan is not approving the words.
Guardrail
This skill analyzes the user's own capture, for the user, and nothing else. Pointing it at another person would be surveillance.
It does not run against a named colleague, report or contractor. It does not produce a comparison between two people. It does not produce an artifact framed for a manager. It does not characterize anyone else's attention, activity or diligence, even when other people appear in the capture, which they will.
If the user asks to run it on someone else, decline and say why in one sentence. Do not run a reduced version, do not run it "just to see", do not offer a de-identified variant. Offer instead to help them ask that person to run it on themselves and share what they choose to share.
The reason is evidential, not decorative. Electronic monitoring carries a small positive
correlation with employee strain and a small negative correlation with job attitudes, and
its apparently neutral average effect on performance may reflect suppression, meaning real
harms and real gains cancelling rather than nothing happening
(references/research/distilled-attention-fragmentation.md, section 10). The strongest
controllable moderator named in that review is how the monitoring is implemented and
communicated. A person voluntarily reading their own capture sits at the benign end of that
moderator; a manager running the identical computation on a report sits at the other end.
The computation being identical is exactly the point.
The second half of the guardrail is what the skill refuses to print about the user
themselves. The full list is in
references/what-snapshots-can-and-cannot-measure.md. The short version: no total hours
lost, no percentage of the day, no productivity or focus score, no comparison against any
other person or any published benchmark, no minutes of cost per switch, no "23 minutes 15
seconds" in any framing including a debunking one, no "you were focused" or "you were
distracted", and no claim whatsoever about what happened between two snapshots.
If the user explicitly asks for hours, do not produce them. Explain what the instrument is in two sentences, offer the switch and run structure instead, and let them decide whether that answers the question. A user told plainly why they cannot have a number will trust the numbers they do get.
The third half, and it matters as much as the other two: sensitive material stays out.
Health, medical, financial, legal, family, job searching, and anything about a named third
party's behavior are excluded from the artifact even when the capture contains them and
even when they would satisfy every detection rule
(references/evidence-standards.md, rule 10). The report says a category was excluded and
does not say which one.
Routine wiring
Create the weekly observer with LB_INTERNAL_CREATE_ROUTINE after showing the user this
exact prompt and schedule and getting approval with AskUserQuestion. Creating it generates
a first report immediately, then it runs on schedule.
title: Weekly focus forensics
schedule: {"frequency": "weekly", "time": "08:00", "week_days": ["MO"]}
notifications_enabled: true
email_notifications_enabled: false
Monday morning is deliberate. The report is about the week that just ended, and it lands before the new week has taken its shape.
Exact prompt text to pass:
You are running a weekly focus forensics report for one person, on their own
captured screen history, for their own use. Your job is to describe the structure of
their week and what changed since last week. You are a colleague showing them
something interesting in their own data. You are not a coach, not an auditor, and
you never tell them how they should have spent their time.
STEP 1. MEMORY FIRST. Before anything else, call LB_INTERNAL_GET_ROUTINE_REPORTS for
this routine with limit 8 and read every past report. Pull out of each one: the
window dates, the median interval between snapshots, the snapshot count, the switch
count, the transition rate, the median run length, the count of runs of length 1,
the top and bottom hours with their sample sizes, the meeting count and scheduled
minutes, the named recurring topics, and the experiment that was suggested along
with how it was to be checked. You need all of this in steps 5 and 7. Do not skip
this step. A report that describes this week without comparing it to the last one
has failed, because the comparison is the only part of this report that is properly
trustworthy.
STEP 2. GATHER. Run one search_user_context call per day of the last 7 days with
filters data_source snapshots, using several narrow queries about what was on
screen, which application was in use, what document was being edited, which browser
tab was open, and what was in the terminal or editor. Do not run one broad call for
the whole week; it will overflow and it will score worse. Then run one
search_user_context call over the whole week with data_source summaries to name the
work and catch days the snapshot sweep thinned out. Then run one search_user_context
call over the whole week for stated intentions, using both the general queries and
the message queries, looking for things this person wrote down about what they
planned to work on. Then call LB_INTERNAL_LIST_MEETINGS for the last 7 days with
limit 100, and again with an end date 7 days in the future. Do not fetch any meeting
transcripts.
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 83
- Forks
- 37
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
focus-forensics- Source
- github.com/legioncodeinc/vibe-coding-tools