---
title: "Prompt Focus"
description: "Shows where your attention went from your own Claude Code and Codex prompts: projects, hours and re-typed asks over 20 weeks, as a local counts-only HTML report. Use when asking where your focus goes."
canonical: "https://orchestkit.yonyon.ai/docs/reference/skills/prompt-focus"
---

# Prompt Focus

Shows where your attention went from your own Claude Code and Codex prompts: projects, hours and re-typed asks over 20 weeks, as a local counts-only HTML report. Use when asking where your focus goes.

<span className="badge badge-gray">Reference</span> <span className="badge badge-green">low</span>

> **Auto-activated**, this skill loads automatically when Claude detects matching context.

<ContextualSkillSidebar slug="prompt-focus" />

> **Prompt Focus** Shows where your attention went from your own Claude Code and Codex prompts: projects, hours and re-typed asks over 20 weeks, as a local counts-only HTML report. Use when asking where your focus goes.


# prompt-focus

Where did your attention go, and what do you keep telling your agents again and again? This skill answers from your own input history, on your machine.

## Quick Reference

| Command | What it does | Output |
|---|---|---|
| `scan` | read history, attribute, aggregate | `agg.json` (counts only) |
| `report` | scan, then build the page | `report.html` |
| `daily [YYYY-MM-DD] [--force]` | append one finished day (yesterday by default), once; today needs `--force` and is written as a partial row that a later run replaces | `daily.jsonl` |
| `demo [path]` | the same page from synthetic data | a shareable demo page |
| `selftest` | synthetic run with privacy asserts | exit 0 or an assert |

Output dir: `$PROMPT_FOCUS_DIR`, default `~/.claude/prompt-focus`. The exact call shape for Claude Code is in [references/claude-code.md](references/claude-code.md).

## Quick Start Example

```bash
python3 "${CLAUDE_SKILL_DIR}/scripts/prompt_focus.py" report     # writes ~/.claude/prompt-focus/report.html
python3 "${CLAUDE_SKILL_DIR}/scripts/prompt_focus.py" demo /tmp/prompt-focus-demo.html   # synthetic data, safe to share
```

Optional `~/.claude/prompt-focus/config.json`:

```json
{"areas": {"billing": ["invoice", "stripe"]}, "brief_patterns": ["^\\s*TASK-\\d+:"], "weeks": 20}
```

## Workflow

1. Run `report`, then open `report.html` for the user.
2. Lead with the verdict line from the page: the top area, prompts per week, and the nudge and words-per-prompt trend.
3. Point at the re-typed asks. Each one has its first-4 vs last-4 weeks trend and a proposed default; the page's copy-as-prompt turns the ticked ones into one request.
4. If the user runs several agents that paste briefs into the terminal, check 20 random rows before trusting the split, and add their brief markers to `brief_patterns`. See [references/how-it-works.md](references/how-it-works.md).

## Key Decisions

- **Your words only.** A paste counts as one event, not as words; a slash command or shell line counts apart; text matching `brief_patterns` is an agent's, not yours.
- **Counts only.** `agg.json`, `daily.jsonl` and the page hold numbers and category names. Prompt text is read in memory and never written.
- **Rolling window.** Always the last 20 weeks ending today (`weeks` in config).
- **Areas.** Your project folder by default; add `areas` regexes in `config.json` to group by topic instead.

## Common Mistakes

- Sharing your real `report.html` publicly: it names your projects. Use `demo` for anything public.
- Reading the split as exact without a control: brief patterns are text rules, and they miss some agent text.
- Expecting other tools: only Claude Code and Codex input history are read.

## Rules

- Read only. Never write to `~/.claude/history.jsonl`, `~/.claude/paste-cache/` or `~/.codex/`.
- Never quote prompt text back in chat beyond the user's own short asks they asked to see.


---

## References (2)

### Claude Code

# Calling prompt-focus from Claude Code

```bash
python3 "${CLAUDE_SKILL_DIR}/scripts/prompt_focus.py" report
python3 "${CLAUDE_SKILL_DIR}/scripts/prompt_focus.py" daily
python3 "${CLAUDE_SKILL_DIR}/scripts/prompt_focus.py" demo ~/Desktop/prompt-focus-demo.html
python3 "${CLAUDE_SKILL_DIR}/scripts/prompt_focus.py" selftest
```

Open the page for the user: `open ~/.claude/prompt-focus/report.html` (macOS) or `xdg-open` (Linux).

A daily row from cron, 04:20 local time:

```text
20 4 * * * mkdir -p ~/.claude/prompt-focus && python3 /path/to/skills/prompt-focus/scripts/prompt_focus.py daily >> ~/.claude/prompt-focus/daily.log 2>&1
```


### How It Works

# How prompt-focus counts

## Sources (read only)

| Source | Field | Notes |
|---|---|---|
| `~/.claude/history.jsonl` | `display`, `pastedContents`, `timestamp`, `project` | what you entered at the Claude Code prompt |
| `~/.claude/paste-cache/<hash>.txt` | paste bodies | used only to tell an agent brief from your own paste |
| `~/.codex/history.jsonl` | `text`, `ts` | what you entered at the Codex prompt |

Transcripts are not read: they hold tool results and agent turns, and they are pruned over time. The input history covers the full window.

## Who wrote it

In order: an empty entry with a paste is a **paste** event (or a **brief** if the paste matches `brief_patterns`); `/x` is a **command**; `!x` is a **shell** line; text matching `brief_patterns` is a **brief**; everything else is **typed**, your words.

Multi-agent setups often paste one agent's brief into another agent's terminal, where it looks typed. The default patterns catch a sign-off like `(worker-one, Claude via Claude Code)` and a brief that opens with `You are <name>.`. Add your own markers:

```json
{"brief_patterns": ["^\\s*TASK-\\d+:", "^\\s*orchestrator:"]}
```

Control: read 20 random typed rows and 20 random briefs; count the wrong ones. Errors usually run one way (agent text counted as yours).

## Areas

Default: the project folder of each prompt (a `.worktrees/<x>` path maps to its repo). The top `max_areas` (8) are kept, the rest go to `other`. To group by topic:

```json
{"areas": {"billing": ["invoice", "stripe"], "docs": ["\\breadme\\b", "docs?/"]}}
```

`markers` draws a dashed line on the stream graph: `{"markers": [{"date": "2026-08-12", "label": "new setup"}]}`.

## Re-typed asks

Seven fixed families (keep going, status, what's next, show it visually, verify, merge, open it). Each shows its share of your prompts in the first 4 vs the last 4 weeks. A family that stays flat after you wrote a rule for it is a sign the rule did not stick; a default in the harness (a hook, an output style) usually works better.
