Projects 5h usage at reset and shows it above the prompt. Optional: install only if you want it.

A collection of skills by hardkoded packaged as plugins for Claude, Cursor, GitHub Copilot, and Codex.
This is a growing collection — more skills will land here over time. Currently:
cronito — an interactive CLI for managing scheduled tasks on your machine, backed by a single system cron entry. This skill vendors a prebuilt, dependency-free bundle, so there's nothing to install to use it. Source lives at hardkoded/cronito. Run /cronito init once to set it up.pr-memory — PR-keyed, on-disk session memory. save snapshots the current session as a handoff-style document (worktree, per-repo branches, every related PR), and load <pr> re-hydrates it later by any of those PR numbers. Works standalone in a single repo, or across a multi-repo workspace if you use one. Memories are pruned automatically once every PR they reference has merged.user-email — an optional Claude Code mod that shows the signed-in account email above the prompt. Not installed with hardkoded; install it separately with /plugin install user-email@hardkoded-skills if you want it.usage-forecast — an optional Claude Code mod that projects where the 5-hour usage window will land at reset, shown above the prompt. Not installed with hardkoded; install it separately with /plugin install usage-forecast@hardkoded-skills if you want it./plugin marketplace add hardkoded/hardkoded-skills
/plugin install hardkoded@hardkoded
Import this repository as a team marketplace, then install hardkoded from the Cursor plugin UI.
Use Chat: Install Plugin From Source and provide:
https://github.com/hardkoded/hardkoded-skills
codex plugin marketplace add hardkoded/hardkoded-skills
codex plugin add hardkoded@hardkoded
hardkoded-skills/
├── .claude-plugin/marketplace.json
├── .cursor-plugin/marketplace.json
├── plugin.json
└── plugins/
└── hardkoded/
├── .claude-plugin/plugin.json
├── .cursor-plugin/plugin.json
├── .codex-plugin/plugin.json
└── skills/
├── cronito/
│ ├── SKILL.md
│ ├── cronito.sh
│ └── dist/cronito.cjs
└── pr-memory/
├── SKILL.md
└── scripts/
Every install path above (Claude, Cursor, Copilot, Codex) resolves skills through a plugin manifest's "skills" field, which points at plugins/hardkoded/skills/ — that's the single copy of each skill in this repo. Each skill only ships its built artifact here — source lives in its own repo (e.g. hardkoded/cronito).
MIT
hooks/register.tsx 75 lines1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register, SessionRateLimit } from 'claude-code'
3
4import type { Forecast } from '../types'
5
6const WINDOW_MS = 5 * 60 * 60 * 1000
7const PACE_MS = 45 * 60 * 1000
8const MIN_PACE_SPAN_MS = 10 * 60 * 1000
9const MIN_ELAPSED_MS = 60 * 1000
10const MAX_SHOWN_PERCENT = 300
11
12const forecast = atom({ plugin: 'usage-forecast', key: 'forecast' } as const, null as Forecast | null)
13
14let samples: { t: number; pct: number }[] = []
15
16async function recompute($: EngineInterface, limits: SessionRateLimit[]) {
17 const window = limits.find(l => l.kind === 'five_hour')
18 if (!window?.resetsAt) return update($, forecast, () => null)
19
20 const now = await $.clock.now()
21 const reset = Date.parse(window.resetsAt)
22
23 const last = samples[samples.length - 1]
24 if (last && window.percentUsed < last.pct) samples = []
25 samples = [...samples, { t: now, pct: window.percentUsed }].filter(s => now - s.t <= PACE_MS)
26
27 const first = samples[0]
28 const latest = samples[samples.length - 1]
29 const recent =
30 first && latest && latest.t - first.t >= MIN_PACE_SPAN_MS
31 ? (latest.pct - first.pct) / (latest.t - first.t)
32 : null
33 const average = window.percentUsed / Math.max(now - (reset - WINDOW_MS), MIN_ELAPSED_MS)
34 const rate = recent ?? average
35
36 const projected = window.percentUsed + rate * Math.max(reset - now, 0)
37 const at = new Date(reset).toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' })
38
39 await update($, forecast, (): Forecast => ({ projected, at }))
40}
41
42export const register: Register = on => {
43 on('session.start', async ($, e, next) => {
44 const result = await next(e)
45 await recompute($, (await $.session.usage()).rateLimits)
46 return result
47 })
48
49 on('session.measure', async ($, e, next) => {
50 if (e.changed.includes('rateLimits')) await recompute($, e.rateLimits)
51 return next(e)
52 })
53
54 on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
55 const beneath = await next(e)
56 const f = await read($, forecast)
57 if (e.props.hasSurvey || !f) return beneath
58
59 const { Box, Text } = $.ui.resolve(e)
60 const over = f.projected >= 100
61 const pct = f.projected > MAX_SHOWN_PERCENT ? `>${MAX_SHOWN_PERCENT}` : Math.round(f.projected)
62
63 return (
64 <Box justifyContent="flex-end">
65 {beneath}
66 <Box marginLeft={2}>
67 <Text color={over ? 'error' : 'success'}>
68 {pct}% by {f.at} - {over ? 'SLOW DOWN!' : 'BURN SOME TOKENS!'}
69 </Text>
70 </Box>
71 </Box>
72 )
73 })
74}
75types/index.d.ts 8 lines1export type Forecast = { projected: number; at: string }
2
3declare module 'claude-code' {
4 interface PluginState {
5 'usage-forecast': { forecast: Forecast | null }
6 }
7}
8