Repository navigation
Conversation
…re the pool (0.16.0) A setup token runs jobs but cannot read usage, so a token account reads it through usage_login, a regular sign-in. Its dir now defaults to the account's own directory, and `skillhook accounts login <name> --usage` signs it in there, so one folder per account holds both credentials. orderPool put accounts with unknown usage behind every measured one, so a pool where only one account's usage could be read sent it every job until it neared a limit. Unknown usage now counts as the fullest band of the accounts with usage left: it takes turns with them, never goes ahead of one measured to have more left, nor behind one measured to have less. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
JOsacky
enabled auto-merge (squash)
November 11, 2026 20:20
JOsacky
force-pushed
the
claude/usage-login-own-dir
branch
from
November 11, 2026 20:20
3ac2ca7 to
96b5556
Compare
JOsacky
added a commit
that referenced
this pull request
Nov 12, 2026
**Version: lands after #84, which takes 0.16.0. This branch is rebased and re-bumped to 0.17.0 once #84 is on main.** ## Why Repositories should declare their timers in `skillhook.yaml` and have that be the source of truth, but a person still needs to switch one off quickly (from Skillhook Cloud) when it misbehaves, without a commit. Today the only off switch is editing the file, so repositories moved their timers into Cloud-owned schedules, which then drift from what the repo declares. ## What - `Scheduler.pause(name, {by, reason, until})` / `resume(name)`. The pause is stored in `jobs/.schedules.json` (not the skill's file), so repo pulls, hook edits and restarts keep it. - While paused nothing fires. The webhook and manual runs still work. Slots that pass count as `skipped` but are never caught up, and they emit no per-slot events, so a week of a 10-minute timer doesn't produce a thousand. On resume, or when `until` passes, it fires from the next slot. - Surfaces: `skillhook schedules pause <name> [--reason] [--until 2h|ISO]` / `resume` (through the running server, or the state file when none runs), `POST /schedules/<name>/pause|resume` (admin), and cloud commands `schedule.pause {name, reason?, until?}` / `schedule.resume {name}` (control class; the next sync carries a fresh snapshot). - `ScheduleStatus.paused` (`{at, by?, reason?, until?}` or `null`) in `schedules list`, `GET /health` and the cloud snapshot. ## Compatibility Older machines refuse a whole sync response that carries an unknown command type, so the cloud must gate `schedule.pause` / `schedule.resume` with `COMMAND_SINCE` = `0.17.0`. That's in the follow-up skillhook-cloud PR, after this publishes. ## Checked `pnpm run check`: typecheck, 528 tests, build, schema, release metadata. New tests cover the scheduler (quiet skip, no catch-up on resume, `until` expiry across a restart, refusals, offline state), the admin route, the CLI and a cloud round trip over `FakeCloud` (pause → snapshot shows it → resume). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
JOsacky
added a commit
that referenced
this pull request
Nov 13, 2026
…nfig (#87) ## Why On 2026-11-12 at 12:20Z, the main operator daemon (0.15.2) restarted onto the newly installed 0.16.0. 0.16.0 rejects `accounts.*.usage_login`, which was written for the unmerged #84. launchd restarted it **128 times** (`Invalid ~/.skillhook/skillhook.json: Unrecognized key "usage_login"`), and for **17 min 20 s** nothing ran: no jobs, no schedules, no hosted ingress. A person-equivalent fix (removing the keys) brought it back. Tracked as RA-019 in the operator's reliability backlog. ## What - `installedAcceptsConfig(paths)` in `src/update.ts` runs `node <installed dist/cli.js> config show --json` with `SKILLHOOK_HOME` set to the server's home. It returns one of three results: - `ok: true`: the new version loaded the config. - `ok: false` with the error: the new version exited non-zero. - `ok: undefined`: the check could not run (spawn error or a 30 s timeout). - The restart-on-newer-version interval in `serve.ts` runs the check before calling `control.restart()`: - **Rejected:** the server logs an `error` once per (version, error), keeps the current version running and checks again every minute. Fixing `skillhook.json` or shipping a later release lets the restart go ahead. - **Unknown:** the server logs a `warn` and restarts as before. A missing node binary (see #71) or a hung check under heavy load must not pin an old version forever. - CHANGELOG has an entry under Unreleased. ## Tests - `src/update.test.ts` has unit cases for each outcome: accepted, rejected with message, bare exit code, missing executable, and timeout. They also check that the child gets this home and not the parent's `SKILLHOOK_HOME`. - An integration case runs the real CLI (`tsx src/cli.ts`) against a valid config and against one with an unknown key. - Local results: `pnpm test` passed 533/533, `typecheck` passed, `build` passed, `release --check` passed. Reversible: the change only skips a restart. It writes no data, and the protocol is unchanged. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: GitHub Actions Bot <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
On the mac mini every Claude job went to
claude-glossa(213 jobs in 24 h vs 3 each forclaude-carimageandclaude-skillhook). Two causes:usage_login, a regular sign-in used only to read usage. Only glossa's worked (it points at~/.claude); the others' live in separate~/.skillhook/usage-logins/<name>folders that are signed out.orderPoolput an account whose usage is unknown (never read, or the reading expired) in a tier behind any account with measured headroom. So glossa, the only measured account, got every job unless it was over 90 % (exactly 11:45–12:20 UTC on Nov 10, when its 5-hour window was full, were the only jobs that went elsewhere).What changes
usage_login.diris optional and defaults to the account's owndir: one folder per account holds both the job token (used by runs) and the usage sign-in (used only by usage reads; Claude Code prefersCLAUDE_CODE_OAUTH_TOKENover the stored sign-in).skillhook accounts login <name> --usage [--sso]runsclaude auth login --email <usage_login.email>in that folder without the token or inherited credentials, then reads the usage. The "Sign in to Claude Code in …" problem names this command.orderPool: back to three tiers (usage left, near-full, limited). Unknown usage is in the first tier and counts as the fullest band among the measured accounts there, so it takes turns with them, never jumps ahead of an account measured to have more left, and never waits behind one measured to have less. One band per account keeps the comparator transitive.accounts.md,operations.md), schema, changelog, version 0.16.0.Tests
usage_logindir defaults;accounts login --usageerrors and the happy path with the fake CLI.pnpm run check: 525 tests pass, schema and release metadata current.Measure
After this ships to the mini and the three usage sign-ins are signed in:
skillhook accounts listshows jobs (24 h) spread acrossclaude-carimage,claude-skillhookandclaude-glossainstead of ~98 % on glossa, and the cloud Account pool shows a recent "Read" time for each.🤖 Generated with Claude Code