Звіт у форматі JSON машиночитний
{
"data": {
"repo": {
"topics": [],
"is_fork": false,
"size_kb": 1065,
"has_wiki": true,
"homepage": null,
"languages": {
"Go": 810107,
"HTML": 50829,
"Shell": 2292,
"Makefile": 1901,
"Dockerfile": 603
},
"pushed_at": "2026-07-21T01:30:04Z",
"created_at": "2025-04-22T03:30:48Z",
"owner_type": "Organization",
"updated_at": "2026-07-21T01:28:34Z",
"description": null,
"is_archived": false,
"is_disabled": false,
"license_spdx": "MIT",
"default_branch": "main",
"license_spdx_raw": "MIT",
"primary_language": "Go",
"significant_languages": [
"Go"
]
},
"owner": {
"blog": null,
"name": "Computational Genomics @IndianaU",
"type": "Organization",
"login": "compgenlab",
"company": null,
"location": "United States of America",
"followers": 0,
"avatar_url": "https://avatars.githubusercontent.com/u/208039369?v=4",
"created_at": "2025-04-17T14:43:35Z",
"is_verified": null,
"public_repos": 12,
"account_age_days": 460
},
"license": {
"state": "standard",
"spdx_id": "MIT",
"raw_spdx": "MIT",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v0.4.0",
"kind": "minor",
"published_at": "2026-07-21T01:32:12Z"
},
{
"tag": "v0.3.8",
"kind": "patch",
"published_at": "2026-07-12T13:10:55Z"
},
{
"tag": "v0.3.7",
"kind": "patch",
"published_at": "2026-07-08T19:26:46Z"
},
{
"tag": "v0.3.6",
"kind": "patch",
"published_at": "2026-07-08T16:14:16Z"
},
{
"tag": "v0.3.5",
"kind": "patch",
"published_at": "2026-07-02T03:07:37Z"
},
{
"tag": "v0.3.4",
"kind": "patch",
"published_at": "2026-07-01T13:16:33Z"
},
{
"tag": "v0.3.3",
"kind": "patch",
"published_at": "2026-06-11T17:21:22Z"
},
{
"tag": "v0.3.2",
"kind": "patch",
"published_at": "2026-06-10T07:59:41Z"
},
{
"tag": "v0.3.1",
"kind": "patch",
"published_at": "2026-06-10T05:06:04Z"
},
{
"tag": "v0.2.8",
"kind": "patch",
"published_at": "2026-06-05T17:11:07Z"
},
{
"tag": "v0.2.7",
"kind": "patch",
"published_at": "2026-06-05T16:41:41Z"
},
{
"tag": "v0.2.6",
"kind": "patch",
"published_at": "2026-06-05T03:53:07Z"
},
{
"tag": "v0.2.5",
"kind": "patch",
"published_at": "2026-06-04T08:50:39Z"
},
{
"tag": "v0.2.4",
"kind": "patch",
"published_at": "2026-06-04T03:11:38Z"
},
{
"tag": "v0.2.3",
"kind": "patch",
"published_at": "2026-06-03T15:35:52Z"
},
{
"tag": "v0.2.2",
"kind": "patch",
"published_at": "2026-05-17T16:44:57Z"
},
{
"tag": "v0.2.1",
"kind": "patch",
"published_at": "2026-05-17T01:52:20Z"
}
],
"recent_commits": [
{
"oid": "661b9ee06db3f16cd5e39286f60fa902d6c88bce",
"body": "fix(queue): single proxied jobs show SLURM status too",
"is_bot": false,
"headline": "Merge pull request #64 from compgenlab/fix/queue-single-slurm-status",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-21T01:28:30Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fe114dcc768d5814af7bec9c3b12b2d7ad19412a",
"body": "…QUEUED)\n\nFollow-up to the collapsed-array change: a non-array SLURM job still showed\nPROXYQUEUED in the status column while array rows showed the SLURM state. Use\neffectiveStatus for the single-job row's status column too, so a proxied job\ndisplays its slurm_status (PENDING/RUNNING/…). The batchq s\n[…]\ne trailing SLURM cell now shows just the id (the status moved\nto the status column).\n\nTest: TestEffectiveStatus. Full suite green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(queue): single proxied jobs show SLURM status too (not just PROXY…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-21T01:21:31Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "053aa2b64af5ec024f222b063fbe6f750654752c",
"body": "fix(queue): collapsed array row shows SLURM state, not just PROXYQUEUED",
"is_bot": false,
"headline": "Merge pull request #63 from compgenlab/fix/queue-array-slurm-status",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-21T01:06:19Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "45171b697c0a4b7f3054e9fe52626d748b725a75",
"body": "A proxied array whose tasks SLURM is actively running still read as PROXYQUEUED\nin the collapsed queue row, because the aggregate/breakdown counted the batchq\nstatus. Use an effectiveStatus that, for a PROXYQUEUED task, surfaces its\nrecorded slurm_status (PENDING/RUNNING/…) — so e.g. 2/33 tasks RUNN\n[…]\nus in their\ntrailing column; this only affects the collapsed array row.\n\nTest: TestArrayProgressUsesSlurmStatus. Full suite green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(queue): collapsed array row shows SLURM state, not just PROXYQUEUED",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-20T19:12:21Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "92d3b3ad1bdf87f38287f59f2650dd69f142a62d",
"body": "feat(queue): collapse arrays to one row + PENDING status for array tasks",
"is_bot": false,
"headline": "Merge pull request #62 from compgenlab/feat/queue-collapse-arrays",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-20T17:43:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "263ae70f54693236fe3db910abd9f50e795f2368",
"body": "…r array tasks\n\nTwo array-display improvements for `batchq queue`:\n\n- Collapse each array into a single summary row by default (array id, aggregate\n status via aggregateArrayStatus, the template's procs/mem/walltime, and an\n \"array <done>/<total> · <status counts>\" breakdown), so a large array no\n\n[…]\n.\n\nTests: arrayProgress, plus the earlier normalizeStates/slurmDisplayID. Full\nsuite green; verified collapse/expand/array-id e2e.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(queue): collapse arrays to one row; seed slurm_status=PENDING fo…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-20T17:28:56Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "ee57d55443706853324656813e79995ffaee1358",
"body": "…ray-slurm-id\n\nfeat(queue): --state/-s filter, and show SLURM array ids",
"is_bot": false,
"headline": "Merge pull request #61 from compgenlab/feat/queue-state-filter-and-ar…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-20T17:06:28Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ecb1d284630fad1c957d0ca1c0aef3970062f844",
"body": "- `batchq queue --state/-s <states>` filters to specific job states\n (case-insensitive, comma-separated, e.g. `-s RUNNING,QUEUED`). When set it\n routes through the /jobs listing (which filters by status) instead of the\n fast queue path; unknown states get a clear error listing the valid ones.\n- T\n[…]\ntes (case/whitespace/blank/invalid), slurmDisplayID (plain,\narray task, array-id-only, job_id-precedence, none). Full suite green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(queue): --state/-s filter, and show SLURM array ids",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-20T17:00:37Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "8c4affece94c48388f9bdd192117296282d06804",
"body": "fix(slurm-runner): resilient handoff write + #SBATCH --comment back-reference for rescue",
"is_bot": false,
"headline": "Merge pull request #60 from compgenlab/fix/slurm-proxy-write-resilience",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-20T16:40:22Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1be1a0bd91020468d97df9248789f1100d7cbd54",
"body": "…scue\n\nsbatch is irreversible, so pair the resilient handoff-write with a durable\nback-reference FROM SLURM to batchq: every generated script now carries\n`#SBATCH --comment=\"{\\\"batchq_id\\\":\\\"<uuid>\\\"}\"` (arrays use \"batchq_array_id\":\nthe array uuid). The comment lives on the SLURM job RECORD — reada\n[…]\nective marshals the JSON and escapes it so sbatch keeps it as one\ndirective token. Test: round-trips the directive back to the id.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(slurm-runner): stamp the batchq id into #SBATCH --comment for re…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-20T16:33:54Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "deb7ff8ed8270706c9018e0b6e5337e131c3c13b",
"body": "…lls on Lustre\n\nArray (and single) jobs were landing stuck at RUNNING with a host but no\nslurm_array_id/slurm_job_id: the runner claims the batch (RUNNING + host), runs\nsbatch (SLURM now has it), then records the id via MarkJobProxied — and on\nLustre that DB write can SQLITE_BUSY/stall. MarkJobProxi\n[…]\nidempotent + wrong-state still\nconflicts), client (MarkJobProxied retries a transient even for a remote runner).\nFull suite green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(slurm-runner): don't lose the SLURM id when the handoff write sta…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-20T16:28:18Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "681049ac4097bcfde1a146bdf804c99d35f368cd",
"body": "feat(submit): idempotent submit so it survives Lustre/NFS transients",
"is_bot": false,
"headline": "Merge pull request #59 from compgenlab/feat/idempotent-submit",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-19T19:46:17Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "57000fb93d4fe0f85d85e0f90c03936a66f8b76a",
"body": "On the Lustre-backed cluster a single `batchq submit` occasionally times out\n(\"Client.Timeout exceeded while awaiting headers\") when a filesystem latency\nspike stalls that job's InsertJob past the 30s cap — cgp then reports a hard\njob failure. We can't speed up the FS, but we can make submit retry s\n[…]\ns\non a transient / does NOT retry keyless), support (IsUUID). Full suite green;\nsubmit_compat unchanged (printed id == client id).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(submit): idempotent submit so it survives Lustre/NFS transients",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-19T06:50:59Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "6957a628544449a354db61faf367df1968032eee",
"body": "fix(cleanup): reword 'kept back' message — dependency-tree preservation, not active deps",
"is_bot": false,
"headline": "Merge pull request #58 from compgenlab/fix/cleanup-blocked-message",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-18T21:27:09Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "798251721ed02878569309c6b37cc7a42469e370",
"body": "…, not active deps\n\nThe old text said \"N not eligible (a dependent is still active)\", which is\nmisleading: the blocking is structural (foreign-key / dependency-tree), not a\nlive dependency — the dependent job is usually already finished (e.g. a newer\njob that completed within the --older-than window\n[…]\ndency trees intact\n (a job that depends on them is being kept)\n\nMessage-only change; the (safe) blocking behavior is unchanged.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(cleanup): reword the \"kept back\" message — it's tree preservation…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-18T20:44:53Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c7c4ef48e99b665357ae697a5f389038fb9a6108",
"body": "fix(cleanup): output text polish + stop WriteTimeout killing the progress stream",
"is_bot": false,
"headline": "Merge pull request #57 from compgenlab/fix/cleanup-output-text",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-18T19:54:29Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "cbf0b3030c51e2e0b78f1e7be3dbb7ba4486649e",
"body": "A cleanup that streams for longer than the server's WriteTimeout (default 2m)\nhad its connection closed mid-stream — the client saw\n\"read cleanup stream: unexpected EOF\" while the server kept working (decoupled),\nso the DB still shrank but the run looked like it failed. This is the\nintermittent EOF \n[…]\n/cleanup_stream_test.go reproduces the exact EOF with a\n1ms WriteTimeout when the deadline isn't cleared, and passes with the fix.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(cleanup): don't let WriteTimeout kill the progress stream",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-18T18:42:00Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "81ccc4fbdfffc20fa8d2061955975d03a81b6271",
"body": "Per feedback on the live output:\n- Pluralize job/jobs internally (\"1 job\", \"2368 jobs\") instead of \"job(s)\".\n- Drop the separate \"Found N …\" line: the action line (\"Archiving N jobs…\" /\n \"Deleting N jobs…\") is the whole story unless some matched jobs can't be\n removed. The Found line now appears O\n[…]\nctive), which is the only case where matched != removed.\n- The action verb is already Archiving vs Deleting per the chosen action.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(cleanup): tidy progress text — plurals, drop redundant Found line",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-18T16:34:56Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "f73d62602cdd392a0a4ae22583db7e7a8efabef3",
"body": "fix(cleanup): make it usable on a large NFS DB — bulk archive, streaming, index, guard",
"is_bot": false,
"headline": "Merge pull request #56 from compgenlab/feat/cleanup-stream-flush-index",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-18T16:16:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b3c96dad1e81e5f023081dca5726a04fe33e09d9",
"body": "The h2 field data showed a single --archive cleanup running ~8 HOURS server-side:\nthe archive path was per-job (GetJob + RestoreJob + CleanupJob = ~18 fsync'd\nstatements per job over NFS). Because cancellation is decoupled, that op kept\nrunning long after the client gave up and blocked every retry (\n[…]\npendencyChain. Full suite green; verified end-to-end\nvia the CLI (bulk archive of a dependency chain + independents, then vacuum).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(cleanup): bulk archive + concurrency guard",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-18T09:31:52Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "5a137b660005e6a0958405994a3a0b38ec6571fd",
"body": "…onger watch\n\nRunning the real cleanup on the 608 MB NFS DB on h2 surfaced three issues once\nread_pool_size was set to 1 (which fixed the SQLITE_BUSY):\n\n1. The client got `POST /admin/cleanup: context deadline exceeded` with no\n progress ever shown. Cause: the handler didn't emit/flush until AFTER\n[…]\ne TestSchemaHasCleanupIndex; full suite green; verified live via the\nCLI (Scanning… → Found N → Archiving x/N → Vacuuming → done).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(cleanup): stream headers immediately, index the candidate scan, l…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-18T08:40:57Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c29954ec1168df4a65204ab35f98626138c43ffa",
"body": "feat(cleanup): stream live progress from the server",
"is_bot": false,
"headline": "Merge pull request #55 from compgenlab/feat/cleanup-progress-stream",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-17T23:02:49Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4b09f0c7c193dc88e30662fb3973ac649b6d448d",
"body": "A bulk cleanup on a large DB could run for minutes returning nothing until\ndone. Stream progress instead: POST /admin/cleanup now emits newline-delimited\nJSON (api.CleanupEvent) as it works — candidate selection, per-batch\ndelete/archive progress, and the vacuum step — ending with a \"done\" (or\n\"erro\n[…]\nstCleanupBulkEmitsProgress; existing CleanupBulk tests updated\nfor the new signature. Full suite green; verified live via the CLI.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(cleanup): stream live progress from the server",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-17T22:56:47Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "603882e6d05a51b4344c94b30e729529b94881e1",
"body": "feat(cleanup): server-side bulk cleanup + no-timeout client fix + --archive UX",
"is_bot": false,
"headline": "Merge pull request #54 from compgenlab/feat/cleanup-scale-and-timeout",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-17T22:51:32Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b849518f016585b210c7d713cc1e3b4c246c0a6b",
"body": "… --archive UX\n\nFollow-ups after the archive/vacuum work exposed real gaps on the 608 MB\nNFS-backed DB on h2.\n\n1. Timeout contract (the reason cleanup still died at 30s on the new binary):\n DialWithOptions overrode Timeout:0 -> 30s, so mustDialClientLongRunning was\n still 30s-capped. Add Options\n[…]\nst.go. Ported the old cmd planner tests\nto the service. Full suite green; verified end-to-end via the real CLI. CLAUDE.md\nupdated.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(cleanup): server-side bulk cleanup; fix no-timeout client; clean…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-17T22:38:51Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "be150d91a71414e107727cbbe9422f2644ad6f0b",
"body": "feat(cleanup): archive to read-only DBs, auto-vacuum, archive fallback lookup",
"is_bot": false,
"headline": "Merge pull request #53 from compgenlab/feat/cleanup-archive-vacuum",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-17T22:08:58Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "757576f0c0a2f6764920277f00bddd3d07d9d4ed",
"body": "…k lookup\n\nRework `cleanup` to require an explicit action and add an offline archive:\n\n- `cleanup --delete | --archive[=NAME]` — no default action; --archive moves the\n selected terminal jobs into a NEW, read-only (0440) archive SQLite DB under\n `[server] archive_dir` (default $BATCHQ_HOME/archive\n[…]\nerns) via\nmustDialClientLongRunning + cmdContextLong.\n\nTests: storage/archive_test.go, service/archive_test.go. CLAUDE.md updated.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(cleanup): archive to read-only DBs, auto-vacuum, archive fallbac…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-17T17:52:22Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "b931a22257602a8b06fee4f4c928341f333cf5ef",
"body": "feat(slurm): emit --gres/--constraint/--nodelist from job resources",
"is_bot": false,
"headline": "Merge pull request #52 from compgenlab/feat/slurm-resource-directives",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-14T12:36:29Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1fbdf2d5bfb71e1c79e5dec83b4f9fc3ed42a9ee",
"body": "The SLURM runner claimed jobs by matching resource.* requirements but never\nforwarded them to sbatch, so a job requesting a GPU (resource.gpu=2, whether\nfrom --resource, #BATCHQ -resource, or #SBATCH --gres) was submitted with no\n--gres and SLURM allocated no GPU.\n\nslurmResourceDirectives now transl\n[…]\n value as a --constraint feature; nodelist_resources emits as\n--nodelist (e.g. host -> a specific node). Surfaced in batchq debug.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(slurm): emit --gres/--constraint/--nodelist from job resources",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-14T12:30:33Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "4d7d35300bbd924bad6e67b59357e49f955eb175",
"body": "feat(submit): generic per-job scheduler passthrough (--custom key=value)",
"is_bot": false,
"headline": "Merge pull request #51 from compgenlab/feat/custom-scheduler-passthrough",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-14T12:16:40Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5d877c853fb79ef2b91f5f6eb8cc231dbd00cf83",
"body": "The spec described batchq status/details --json, which shipped in f28cc63\n(merged to main). The handoff doc has served its purpose.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: remove completed status --json handoff spec",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-14T12:11:18Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "308b571ba94f62ffcedb42586bbdf439618cc2a5",
"body": "Account and partition could previously only be set on the SLURM runner\n(--slurm-account/--slurm-partition), applying uniformly to every job. A\n#SBATCH -A/-p in a submitted script was silently dropped.\n\nAdd a generic, scheduler-agnostic passthrough stored under a new custom.\ndetail prefix (mirroring \n[…]\n are rejected. batchq's core does not interpret\ncustom.* values; a future PBS/SGE proxy can map the same details to its own\nflags.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(submit): generic per-job scheduler passthrough (--custom key=value)",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-14T12:09:54Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "a48c459f69d8866c0c95aa2de7adece1c68a3506",
"body": "feat(status): add --json to status and details",
"is_bot": false,
"headline": "Merge pull request #50 from compgenlab/feat/status-json",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-12T13:07:23Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f28cc63db3daefc50d7fa6ba85f60412f4ced9da",
"body": "Emit a JSON array of api.JobDTO from `batchq status --json` and\n`batchq details --json`, one element per resolved job (array ids\ncontribute all member tasks, index-sorted). Unknown ids are omitted\nand exit 0, matching --porcelain. The DTO is emitted as-is, so cgp's\n`cgp status --json` can populate p\n[…]\netails) for batchq-backed jobs instead of\nscraping --porcelain/-e.\n\nSee docs/cgp-status-json-handoff.md for the consumer contract.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(status): add --json to status and details",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-12T12:30:47Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "de137f4471d0245b6d68d08fdddb626bcfdc88a7",
"body": "feat(priority): apply top/nice across a whole array",
"is_bot": false,
"headline": "Merge pull request #49 from compgenlab/feat/web-api-gateway",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-08T16:23:55Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "354d6cd062e608328f3153201dbc40fc2f08d516",
"body": "Extend the priority commands to accept an array id: top/nice now dispatch\nwhole arrays to a new atomic POST /arrays/{array_id}/priority endpoint\n(one UPDATE over every eligible QUEUED/WAITING/USERHOLD task), while single\njobs/tasks continue through the per-job endpoint. Mirrors the existing\narray cancel/hold/release vertical slice across api/client/server/service/storage.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(priority): apply top/nice across a whole array",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-08T16:19:21Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "0079fca7c12bc2439f304ed98305d0249e897890",
"body": "feat(slurm): store submitted sbatch script on array tasks",
"is_bot": false,
"headline": "Merge pull request #48 from compgenlab/feat/web-api-gateway",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-08T16:11:04Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b44cb032a3cea44f3f5b2372e5851613c0dbdaf2",
"body": "Array tasks now record slurm_script in their running details, so\n`batchq details <array-task-id>` shows the exact `--array=<indices>%N`\nscript the task was submitted with (matching single-job behavior),\ninstead of falling back to the raw job body. A drip-fed array is\nsubmitted as several batches (e.\n[…]\npt belongs with the task, not the\nlogical array. Duplication is bounded by the batch size (live-queue\nbudget), not the array size.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(slurm): store submitted sbatch script on array tasks",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-08T16:02:10Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c296104d812cd0b7ca9c43ccc2598f182a3aec63",
"body": "feat(web): combined UI + REST API gateway (batchq web --api)",
"is_bot": false,
"headline": "Merge pull request #47 from compgenlab/feat/web-api-gateway",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-08T14:15:41Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "14c9d0e8a38ef58a5892af6895d560547a51e8d4",
"body": "JobDef.Print() iterated Details/RunningDetails in insertion order, so\n`batchq details` showed the keys in a different order each time. Print a\nkey-sorted copy of each (the model itself is left untouched; \"script\" and\n\"slurm_script\" are still extracted and printed last).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(details): sort job detail keys alphabetically",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-08T14:01:00Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "302cab6c8c79c0d6a07919cd78e332cd78c619f8",
"body": "On a TCP listener, instead of serving an unauthenticated surface, `batchq web`\nnow generates any missing credential, prints it to stderr, and persists it to\nthe config file so restarts reuse it:\n\n- missing UI password -> random 16-char password (user \"admin\")\n- --api with no token -> random \"sk-\"+2\n[…]\nsecure-by-default behavior.\n\nTests: RandomString/RandomToken, SaveConfig round-trip + minimality + 0600 +\npreserves existing keys.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(web): generate & persist missing gateway credentials",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-08T13:30:42Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "bef20cd201730fe0f2f45d1418340a661a660104",
"body": "`batchq web --api` now serves both surfaces on one listener: the browser UI at\n/ (HTTP Basic, admin + [web] password/BATCHQ_PASSWORD) and the REST API\nreverse-proxied under /api/ (bearer [batchq] token/BATCHQ_TOKEN). The web\nprocess stays a REST client and forwards /api/* to the backend it's connect\n[…]\n gateway auth (both surfaces), reverse-proxy token injection, transport\nprecedence, array-details line. Docs updated in CLAUDE.md.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(web): combined UI + REST API gateway (batchq web --api)",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-08T13:15:53Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "f6c692bb10af945f1e4cf511a8725b3dd689de49",
"body": "fix(list): defer hydration on detail-filtered listings",
"is_bot": false,
"headline": "Merge pull request #46 from compgenlab/fix/detail-filter-defer-hydration",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-08T00:57:50Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9ee2e9854371c90db2b24fbd72b9b34c2fffec9a",
"body": "`batchq details <array_id>` (and any --array-id/--run-id/--output/--input\nfilter) went through Service.ListJobs, which listed every job row in the DB,\nhydrated all of them (loadJobRelations = 5 SELECTs per job, serialized on the\nsingle SQLite connection), then filtered down to the matching set in me\n[…]\nordering are preserved; only the wasted\nhydration is removed. The slurm runner's PROXYQUEUED path still passes\nloadRelations=true.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(list): defer hydration on detail-filtered listings",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-08T00:33:45Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "cdf37571ee3771477a8064166df1847c7ad81f4f",
"body": "fix(queue): bound --since/--before in SQL, not in memory",
"is_bot": false,
"headline": "Merge pull request #45 from compgenlab/fix/queue-since-sql-bound",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-02T03:04:36Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ee4dc2de4b6f67ca3a914a74110d76e331a09ed6",
"body": "`batchq queue --since ... --all` timed out (context deadline exceeded)\nbecause adding a time filter rerouted the queue view from the fast\n/queue endpoint (one JOIN query) to the general /jobs endpoint, which\nloads full relations (5 queries per job) and then filtered since/before\nin Go — O(5N) round-\n[…]\ns, still use /jobs.\n\nAdd TestGetQueueJobsFiltersBySubmitTime; existing\nTestListJobsFiltersBySubmitTime now exercises the SQL path.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(queue): bound --since/--before in SQL, not in memory",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-02T03:01:54Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "90a9a208fa381b3913a9937d9c900cec746710d3",
"body": "chore(ci): bump artifact/release actions off deprecated Node 20",
"is_bot": false,
"headline": "Merge pull request #44 from compgenlab/chore/bump-ci-actions",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-01T14:17:25Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6fdebd6c0b9725c21b8dd90b3c4dccf8b1dd0531",
"body": "actions/upload-artifact@v4, actions/download-artifact@v4, and\nsoftprops/action-gh-release@v2 were being force-run on Node 24 with a\ndeprecation warning. Bump to the current Node 24-native majors (v7 / v8\n/ v3). Usage is limited to stable inputs (name+path uploads/downloads,\nfiles + GITHUB_TOKEN for the release), so no config changes are needed.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_013JLuEtYbQqJ5iUzJGQPRT4",
"is_bot": false,
"headline": "chore(ci): bump artifact/release actions off deprecated Node 20",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-01T14:12:18Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "09b3f9a35a92e2aca999c95b4fb0632ed8da650e",
"body": "feat(queue): add --since/--before submit-time filters",
"is_bot": false,
"headline": "Merge pull request #43 from compgenlab/feat/queue-since-before",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-01T13:14:23Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "cbfd9f25e4f6013f457a68ad47d783100300d40d",
"body": "`batchq queue` can now be restricted to a submit-time window, e.g.\n`batchq queue --all --since 2026-06-30 --before 2026-07-01` (yesterday)\nor `batchq queue --all --since 1d` (last 24h).\n\nBoth flags accept absolute dates (2006-01-02, local midnight), local\ndatetimes, RFC3339, and relative age-ago dur\n[…]\n-array-id\nintersect pattern (no storage-interface change).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_013JLuEtYbQqJ5iUzJGQPRT4",
"is_bot": false,
"headline": "feat(queue): add --since/--before submit-time filters",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-07-01T13:11:38Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "f6214b8285d2dc0b0a6b7622a3caa4066506d4e4",
"body": "docs: update cgpipe repo URL to compgenlab org",
"is_bot": false,
"headline": "Merge pull request #42 from compgenlab/docs/cgpipe-repo-url",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-18T06:13:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3f741566f5e77dba1a352139c1f10d266bbb3ca9",
"body": "Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: update cgpipe repo URL to compgenlab org",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-18T06:11:20Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "8ad37aea201e001356a63f46140265c40c002779",
"body": "chore: rename Go module to github.com/compgenlab/batchq",
"is_bot": false,
"headline": "Merge pull request #41 from compgenlab/chore/rename-module-compgenlab",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-18T04:21:48Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7730ed88bc4725b824978509562c6e1cbeea410b",
"body": "Repo moved from the mbreese user to the compgenlab org on GitHub.\nMechanical rewrite of github.com/mbreese/batchq -> github.com/compgenlab/batchq\nacross all import paths, go.mod, Makefile ldflags, and docs. The unrelated\ngithub.com/mbreese/cgpipe link in docs/overview.md is left intact.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore: rename Go module to github.com/compgenlab/batchq",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-18T04:08:49Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "007097068880b0e94ba4d1db57490aa4bb320a0c",
"body": "fix(slurm): submit gather jobs that depend on arrays",
"is_bot": false,
"headline": "Merge pull request #40 from mbreese/fix/slurm-array-gather-deps",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-16T16:34:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "66b5fec233fa66e2938188f58505dd79378e4a4b",
"body": "A gather submitted with `--deps afterok:<array_id>` was canceled the moment\nthe SLURM runner tried to submit it, with \"missing slurm_job_id\". The afterok\ndeps fan out to array tasks, which record slurm_array_id + slurm_task_index\n(never slurm_job_id), but slurmAfterOkDirective only read slurm_job_id\n[…]\nt.\n\nAdds regression tests for whole-array collapse, multi-sub-array collapse,\npartial per-element fallback, and proxied-promotion.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(slurm): submit gather jobs that depend on arrays",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-16T11:34:17Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "7c8f000dff99354ab4f39cc3a6a5ac4b5193d961",
"body": "feat(deps): resolve <arrayid>_<index> task addresses in dependency specs",
"is_bot": false,
"headline": "Merge pull request #39 from mbreese/fix/task-address-deps",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-15T20:13:54Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4511a762887b48feb0db161ff2faa1e1861556fc",
"body": "The service layer resolved whole-array ids and plain job UUIDs in afterok/\naftercorr specs, but not SLURM-style `<arrayid>_<index>` task addresses — only\nthe CLI resolved those, client-side. So a dependency on a single array task\n(e.g. a gather wired per-task) failed submission with\n`storage: dep <a\n[…]\nine per id (queried token echoed in field 0; arrays\ncollapse to one aggregate status) for external tools that parse status output.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(deps): resolve <arrayid>_<index> task addresses in dependency specs",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-15T19:26:53Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "ede96293f6b9575f36ec898260508667f9912d6f",
"body": "Normalize job names so SLURM submission can't break",
"is_bot": false,
"headline": "Merge pull request #38 from mbreese/fix-slurm-jobname-spaces",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-11T17:19:02Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4f3676f407d3d9cc5f906d5fa156dc2f270cbf9a",
"body": "A job named \"Count reads per sample (extended walltime)\" was rejected by\nsbatch with \"Invalid directive found in batch script: reads\": the SLURM\nrunner interpolated the name into `#SBATCH -J` unquoted, so the second\nword was parsed as a stray directive.\n\nAdd jobs.NormalizeName: every character outsi\n[…]\n) so batchq never stores a name\nwith whitespace; the SLURM runner reuses it as an idempotent guard when\nbuilding the -J directive.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Normalize job names so SLURM submission can't break",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-11T17:14:48Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "d4da4571c70c8618f5fcf4e8f2a210c3bff471de",
"body": "status: add -s/-b/-e/-t timestamp flags",
"is_bot": false,
"headline": "Merge pull request #37 from mbreese/status-time-flags",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-10T21:49:41Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fcfbbd397d7c7b0b25e7d6c5c625b61de467fb57",
"body": "Add opt-in boolean flags to `batchq status` to append lifecycle\ntimestamps to the status line, combinable in any order (e.g. -sbet):\n\n -s/--submit SubmitTime\n -b/--begin StartTime\n -e/--end EndTime\n -t/--walltime WallTime (end-start; now-start while RUNNING)\n\nTimes are RFC3339 UTC \n[…]\nseable). Default output (no flags) is unchanged\nso downstream parsers are unaffected. Reuses timeOrZero and\njobs.WalltimeToString.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "status: add -s/-b/-e/-t timestamp flags",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-10T21:45:55Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "71819469accbf51ab86304704e1e08e303c5a49d",
"body": "Add `batchq backup` command (VACUUM INTO snapshot)",
"is_bot": false,
"headline": "Merge pull request #36 from mbreese/backup-command",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-10T07:56:30Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f6cebf822d5337ca6229633801a40bd7b71ca3dd",
"body": "Snapshot the SQLite DB via the running server's own connection, so no\nsecond process ever opens the live file — the safe way to back up a DB on\nNFS/Lustre, where running `sqlite3 .backup`/`.dump` externally would open a\nsecond connection (the cross-process case the single-server model avoids).\n\nThre\n[…]\ntegrity_check; refuses an\nexisting destination) and service (default-path resolution; explicit and\nexisting-destination handling).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Add `batchq backup` command (VACUUM INTO snapshot)",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-10T07:52:24Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "93cfb6a913b33895591915af55ada3ea0c323033",
"body": "slurm runner: --slurm-min-array and --slurm-full-array batch gates",
"is_bot": false,
"headline": "Merge pull request #35 from mbreese/slurm-array-batch-gates",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-10T05:02:10Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "23302fc978d622e7093c073cc28adf0ed7af0f07",
"body": "…unners)\n\nDocument the three runtime roles and how to invoke each: the server (and\nautospawn / batchq stop), the client subcommands (submit/queue/status/\nhold/cancel/web), and the two runners — the long-lived simple runner and\nthe one-shot cron'd SLURM proxy runner, including the new array-batch\ngate flags. Also lists the global client flags (--remote/--token/\n--no-autospawn/--restart-server/--log).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: add a \"Running batchq\" section to CLAUDE.md (server, clients, r…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-10T04:56:40Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "071d4f6af7cbf87fb47d48821a98d830d1090c93",
"body": "The SLURM proxy runner drip-feeds a large array across passes, bounded by\nmax_slurm_jobs/max_jobs. Once an array is mostly through, each freed slot\ntriggers a tiny `sbatch --array`, which is wasteful and noisy.\n\nAdd two array-batch gates to ClaimNextArrayBatch (decided before claiming,\nsince claims \n[…]\nases (claim/defer/tail/fall-through, full-array), runner\nclampMinArray. Docs: CLAUDE.md, docs/configuration.md, batchq debug rows.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "slurm runner: --slurm-min-array and --slurm-full-array batch gates",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-10T04:45:06Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "7f8e715f6157ec6d9e7901e4856604370c2623aa",
"body": "Close the idle-handoff SQLITE_BUSY window: release the socket after the DB",
"is_bot": false,
"headline": "Merge pull request #34 from mbreese/fix-idle-cull-handoff-race",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-09T04:00:55Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "cb7b5523b16c2aa32c093332618cb809261c8e96",
"body": "…l_size)\n\nAll DB access went through one connection (SetMaxOpenConns(1)), serializing\nreads behind reads and behind writes — under cgpipe's status-poll bursts a\nsingle slow NFS read/write blocked everything. SQLite's rollback-journal\nlocking allows concurrent readers (each takes a SHARED lock; reade\n[…]\nConsistent (distinct pool of N; reads see committed\nwrites; 20 concurrent reads succeed during a write). Full suite + -race green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "storage: optional concurrent reads via a read pool ([server] read_poo…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-08T23:56:02Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "4890cea88f12cabd70d74e7e320920d797e005b0",
"body": "…ingle-server SQLITE_BUSY)\n\nField diagnosis (via --log): SQLITE_BUSY fires with a SINGLE server running.\nThe failing POST waited exactly busy_timeout (5.0s) then failed, and the server\nserved nothing else meanwhile — so another *connection* held a write lock, even\nthough only one server exists.\n\nRoo\n[…]\npagated context.Canceled).\n\nIf churn ever recurs, the heavier follow-up is pinning a dedicated *sql.Conn for\nthe process lifetime.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "storage: decouple ALL DB access from request cancellation (the real s…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-08T23:15:25Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "1bde55fc4fd4b44eb4d39f621b84bea757c04208",
"body": "…e spawned server)\n\nThe lifecycle log path from [batchq] log / --log now resolves a leading ~ to\nthe user's home dir. OpenDebugLog already ran it through ExpandPathAbs; this\nalso expands it to an absolute path in the client BEFORE passing --log to the\nautospawned server, so the child opens the exact\n[…]\n [server] db and [job_defaults] wd/stdout/stderr.)\n\nTest: TestOpenDebugLogExpandsTilde asserts ~/logs/debug.log lands under $HOME.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "debug log: expand ~ in the config log path (and when handing it to th…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-08T22:47:10Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "3429d9ebe9d276441e8896af2e462b3eda207372",
"body": "…rrors) with PIDs+timestamps\n\nStop guessing at \"too many servers\"/SQLITE_BUSY — instrument it. A new\nopt-in lifecycle log records, with a timestamp and PID on every line, what\nthe client and the servers it autospawns are doing, to one shared file so\noverlapping server PIDs are obvious.\n\nEnable with \n[…]\nwith a short idle timeout) the\nordered \"db closed\" appearing before \"serve exit\" — confirming the socket is\nreleased after the DB.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "debug: add --log lifecycle log (client/server spawns, shutdowns, DB e…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-08T22:26:36Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "9aea104d5edadc4857259f3d3c9f1f1fdba659b2",
"body": "…ased after DB)\n\nA 500 SQLITE_BUSY from a *running* server means two server processes had\nthe DB open and in a transaction at once. On a single host with autospawn\nthe remaining way that happened was the idle-cull -> respawn handoff, and\nthe bug was an ordering inversion: the unix socket — which *is\n[…]\nhe gate.\n- client: a draining handoff is transparently retried to success; disabled\n autospawn surfaces the 503 without retrying.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "server/client: close the idle-handoff SQLITE_BUSY window (socket rele…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-08T20:01:49Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "ae2841bbf45775c0c7c2d1d0e96f42ab7572f0fd",
"body": "server: win single-instance election before opening the DB",
"is_bot": false,
"headline": "Merge pull request #33 from mbreese/fix-sqlite-busy-startup-race",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-08T06:18:17Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4ce742637525f888257678b947e3438f2f8dde26",
"body": "…_BUSY fix)\n\nRemove the DB flock added earlier — it was a backstop that masked the\nproblem. On a single host the unix socket is already a correct\nsingle-instance lock and one server (MaxOpenConns(1)) serializes all\naccess, so it can never report SQLITE_BUSY. The error means a SECOND\nserver got start\n[…]\nurrent cold-start\nsubmits, idle-restart loop, and kill -9 stale-socket recovery all yield\nexactly one server and zero SQLITE_BUSY.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "server/client: prevent duplicate servers on one host (the real SQLITE…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-08T06:04:13Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "4442d832022f2596fef9b5bae29de5d2ca96241d",
"body": "Even with election-before-open, SQLITE_BUSY can still occur when two\nprocesses open the same DB file via DIFFERENT election tokens — the\nclassic HPC case where unix sockets are host-local but $BATCHQ_HOME/the\nDB sit on a shared (NFS/Lustre) filesystem, so a client on another node\ncan't reach the one\n[…]\nn SQLITE_BUSY — /healthz is\nauth-exempt so the probe finds a server regardless of token, and a token\nmismatch is a 401, not a 500.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "storage: take an exclusive DB lock so a second opener fails clearly",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-08T05:37:51Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "f74afb81d795a0fd63752dbd1dd793698d22a7f9",
"body": "Fixes \"database is locked (5) (SQLITE_BUSY)\" on submit. The server opened\nthe SQLite DB (storage.Open -> Ping + schema apply, taking locks) BEFORE\nthe socket-bind election. When many `batchq submit` clients autospawn a\nserver from a cold start, N servers all opened the same DB concurrently:\neach tak\n[…]\neout(5000ms),\nwhich covers it (single idle old server, simple lock wait, DB closed\nwithin ms by the existing defer store.Close()).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "server: win single-instance election before opening the DB",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-08T04:52:37Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "507ab01411a34e1a6b997562db02a831db96f9d2",
"body": "Fix sticky SQLite tx-poisoning on submit; add server status to `batchq debug`",
"is_bot": false,
"headline": "Merge pull request #32 from mbreese/fix-sqlite-tx-poisoning",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-08T04:27:09Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "80433997fe89348ec9b453fd0d183ff36c66eac7",
"body": "`batchq debug` now ends with a server-status section that probes the\nconfigured endpoint (no autospawn) and reports whether a server is\nrunning, its PID, and instance id -- i.e. can it be reached / PINGed.\nFor an unresponsive local unix socket it distinguishes a down server\nfrom a stale leftover soc\n[…]\nincludes its os.Getpid() in the /healthz response\n(api.HealthResponse.PID); add client.HealthStatus to return the parsed\nresponse.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "debug: report server status (running / PID / pingable)",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-08T04:23:15Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "20d4eea5792ae4a03d4feb4b6a0a096dee1d5184",
"body": "A canceled request context racing a BEGIN leaves modernc/sqlite's\nconnection inside a transaction when database/sql returns it to the pool.\nWith SetMaxOpenConns(1) that single poisoned connection then fails every\nlater BeginTx with \"cannot start a transaction within a transaction\"\nuntil the server r\n[…]\n through it.\n\nAdd regression tests: recovery from a poisoned connection, and a write\ncompleting under an already-canceled context.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "storage: fix sticky \"cannot start a transaction within a transaction\"",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-08T04:18:09Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "4a45711a6fff8aacb63d7e75618baa0c6e596b9b",
"body": "Captures the \"root identity proxy → SLURM-free multi-user HPC\" idea:\na root-owned batchq proxy on login/submit nodes captures kernel-attested\nuid/gid and forwards a trusted identity assertion to a remote\nbatchq-server, so a remote deployment can verify who submitted a job\nwithout a local root socket\n[…]\n\napplyPeerIdentity override, and uid-based ownership authz.\n\nInternal note, intentionally not wired into the published docs index.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: add internal PLAN.md for future-direction notes",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-05T21:40:03Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "381822e345ec45013e8b820a0399bc7b45f35436",
"body": "…, backfill PR #30 unit coverage (#31)\n\nFollow-up to the PR #30 robustness review.\n\n- runner/simple.go: a job whose stdout/stderr file (or its dir) can't be\n created now fails loudly via failClaimedJob instead of running with\n discarded output and reporting SUCCESS. cleanup() releases anything\n a\n[…]\nomDef round-trip + ParseStatus, FindArrayMembers.\n\ngo build/vet/test ./... pass; go test -race ./runner ./storage ./service clean.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "runner/tests: fix silent output-file failures, remove inert WaitDelay…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-05T17:06:54Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "000b2695bbcd6a165328624849178813c7d19a4d",
"body": "… leaks (#30)\n\n* chore: add test-race target, restore smoke runner, drop stray files\n\n- Makefile: add a CGO-enabled test-race target (race detector needs CGO,\n which the pure-Go default build disables).\n- test.sh: restore the documented end-to-end smoke runner (it had been\n overwritten by a user j\n[…]\njects reserved/whitespace names like submit does.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Runner robustness: fix data race, daemon-killing panics, and resource…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-05T16:38:16Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "84ebf75b43bd06f11732975f6f8b156c7933145b",
"body": "Runner host cluster",
"is_bot": false,
"headline": "Merge pull request #29 from mbreese/runner-host-cluster",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-05T03:49:42Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "97fc6ec438b61931ba3c3591ef688d897247d568",
"body": "Routing a job to the right cluster/host needs BOTH sides set: the runner\nadvertises, the job requires. The runner side existed; this adds the submit\nside so a user configures their cluster once instead of typing --resource\nevery time.\n\n- `batchq submit` gains --cluster / --host shorthands and [job_d\n[…]\nnner knobs.\n\nTests: submit --cluster/--host + config default + precedence; withResource;\nrunner advertises host alongside cluster.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "submit: default required cluster/host resources (multi-cluster routing)",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-05T03:42:42Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "92a350e2424d453cd89d587889dccee301c6ba06",
"body": "Previously every `batchq run` generated a fresh UUID runner id, so the\nserver's Runners view accumulated a new row per invocation. The id is now\nstable by default so a runner shows as one row that updates in place.\n\n- Runner id resolution: --runner-id flag > [*_runner] runner_id config >\n hostname \n[…]\nsimple_runner.resources] / [slurm_runner.resources]; the\n--cluster convenience and these remain the way to advertise capabilities.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "runner: stable runner id (defaults to hostname) + simple max_jobs",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-05T03:35:13Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "45595ae4a817d525e3df0046d8ada81483ad74b2",
"body": "A runner connecting to a (remote) server now advertises which machine it\nruns on and, optionally, the cluster it belongs to, so the server's Runners\nview can show the host and route cluster-tagged jobs.\n\n- api.ClaimJobRequest/ClaimArrayRequest gain a Host field; client.ClaimNextJob\n /ClaimNextArray\n[…]\nter knobs.\n\nThe server treats Host as advisory metadata; an older server simply ignores\nthe field, so this is backward-compatible.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "runner: advertise hostname + cluster on claim",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-05T01:25:12Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "cf2cc9781f052bde70565c8b6a97fd9c2a1dd596",
"body": "docs: reconcile how-it-works/security/transport wording after the token + TCP merges",
"is_bot": false,
"headline": "Merge pull request #28 from mbreese/docs-post-merge-sync",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-05T00:41:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f8e92348ceb9587b0b7e7744a32dbb342107132a",
"body": "Accuracy nits in the \"how the system works\" walkthrough:\n- the client diagram listed a `show` box (no such command) -> `queue`\n- the job-lifecycle step cited POST /jobs/{id}/status, but runners report\n via the runner endpoints (/runners/{id}/jobs/{id}/end) -> corrected\n- the server/ layout line said \"unix-socket listener\" only -> listener\n is unix socket or TCP, plus the shared-token auth middleware\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: tighten the architecture how-it-works explanation",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-05T00:38:06Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "aa28267ba135c4e7912bedc02e89b45a0c12bc57",
"body": "…atures\n\nThe arrays/resources docs branch and the shared-token/TCP branch landed\nin parallel, so the security and transport prose written on the docs\nbranch predated those features and went stale on merge. Fix:\n\n- \"bearer-token auth not yet implemented\" / \"isn't implemented yet\"\n (overview, running\n[…]\nA couple of leftover `show`-as-command references (README client list,\n configuration multiuser row, CLAUDE.md) -> real commands.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: reconcile security/transport wording with merged token + TCP fe…",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-04T23:12:14Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c7f49a3bf6483fe142d64bc414f4fcaf39ed631e",
"body": "docs: document job arrays, generic resources, and the full command set",
"is_bot": false,
"headline": "Merge pull request #26 from mbreese/docs-arrays-resources",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-04T23:06:51Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f3b9c466f1779c11b23f2809c260d06fa92df136",
"body": "server: shared-token auth + optional TCP listener",
"is_bot": false,
"headline": "Merge pull request #27 from mbreese/server-shared-token",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-04T23:06:35Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4d05acada0dbe11df68efcd885d1449c27b7395e",
"body": "The API server could only bind a unix socket, which is awkward in\ncontainers/orchestrators. Add an opt-in `tcp://host:port` listen form.\n\n- server: listen() handles tcp:// via listenTCP (plain HTTP; EADDRINUSE\n -> ErrAlreadyRunning; no socket election/cleanup/ownership monitor,\n which are unix-onl\n[…]\n; relaxed CLAUDE.md from \"never binds TCP\" to \"never\n terminates TLS\".\n\nDefault is unchanged (unix socket); TCP is purely opt-in.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "server: support binding a plain-HTTP TCP port (tcp://host:port)",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-04T23:02:13Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "dc84ec574aeb8a153d15c0af14a8a9eb29ce4d21",
"body": "Adds a single-shared-secret bearer-token gate so a user can run their\nown network-exposed batchq server \"secure-enough\" without standing up\nthe managed multi-tenant server. Real per-user identity stays the\nmanaged server's job.\n\n- support/config: `[server] token` knob + `BATCHQ_SERVER_TOKEN` env\n o\n[…]\nrver = per-user); update CLAUDE.md.\n\nBackward compatible: with no token configured the server enforces\nnothing, exactly as before.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "server: add shared-token auth for self-hosted remote servers",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-04T22:28:32Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "f7a7130b96a096e98f8a776ecf6d1df9948a09b7",
"body": "Found during a prose-accuracy audit of the remaining pages:\n\n- overview.md listed `show` as a client subcommand (no such command);\n replaced with the real read commands. Also corrected the \"no per-user\n authentication today\" claim: the server always derives unix-socket\n client identity from kerne\n[…]\nb.md: documented the array UI the arrays change added — the queue\n array column / `?array_id=` filter and the job-page Array tab.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: fix accuracy gaps in overview, running-jobs, and web pages",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-04T21:41:08Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "1ca6e79f2d8afdd2ce4b5ea0694f546d70a2b9c5",
"body": "Several user-facing commands had no real documentation: summary, top,\nnice, and license had none at all, and cleanup/hold/stop only appeared\nas one-line mentions. Add docs/managing-jobs.md documenting the full\ninspection and management surface:\n\n- queue (every filter/sort flag), summary, search, sta\n[…]\nersion/debug/license\n\nWire it into the docs index and cross-link from submitting-jobs.md,\njob-arrays.md, and the top-level README.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: add a Managing jobs page covering the remaining commands",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-04T21:31:50Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "6451ba144bac89f233eb13dcfd6ce221b79b0df7",
"body": "- `--slurm-acct` is not a real flag; the runner flag is `--slurm-account`.\n- The `[slurm_runner]` quick example used `max_jobs = 200` with a\n \"concurrent jobs visible to SLURM\" comment — that's `max_slurm_jobs`\n (live SLURM-queue cap), matching the `--slurm-max-jobs 200` line above.\n `max_jobs` is the per-invocation submit cap.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: fix wrong SLURM runner flag and config key in README",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-04T21:19:30Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "d7b619af5e29cddde3ab641f779958266b12d137",
"body": "There is no `batchq show` parent command — queue/details/status are\ntop-level — and the queue file-tag filters are `--output`/`--input`,\nnot `--produces`/`--consumes`. Correct every occurrence across the\ndocs and the top-level README:\n\n- `batchq show queue|details|status` -> `batchq queue|details|status`\n- generic `batchq show` stand-ins -> `batchq queue`\n- `batchq queue --produces/--consumes PATH` -> `--output/--input PATH`\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: fix stale command/flag references",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-04T20:11:37Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "5cb10c9459b55baaa8e32eaa2afc0d0c4b327304",
"body": "Document two features that shipped but were undocumented:\n\n- docs/job-arrays.md (new): --array spec forms, %A/%a per-task output\n placeholders, the per-task env vars (BATCHQ_/SLURM_/PBS_/SGE_ task\n index), batch management (hold/release/cancel on an array id and the\n <array_id>_<index> task addre\n[…]\nURM translation/array\nreconciliation note (slurm.md), the docs index (docs/README.md), and\nquick examples in the top-level README.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: add job-arrays and generic-resources guides",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-04T20:08:12Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "81b4a81bb357e4abddae8e95becfa129841cdb55",
"body": "Add job arrays with batch management, SLURM proxy, and web view",
"is_bot": false,
"headline": "Merge pull request #25 from mbreese/job-arrays",
"author_name": "Marcus Breese",
"author_login": "mbreese",
"committed_at": "2026-06-04T18:12:59Z",
"body_truncated": false,
"is_coding_agent": false
}
],
"releases_count": 17,
"commits_last_year": 211,
"latest_release_at": "2026-07-21T01:32:12Z",
"latest_release_tag": "v0.4.0",
"releases_from_tags": false,
"days_since_last_push": 1,
"active_weeks_last_year": 14,
"days_since_latest_release": 1,
"mean_days_between_releases": 5
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": false,
"has_contributing": false,
"health_percentage": 25,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"ecosystem": {
"packages": [
{
"name": "github.com/compgenlab/batchq",
"exists": true,
"license": null,
"keywords": [],
"ecosystem": "go",
"matches_repo": true,
"registry_url": "https://pkg.go.dev/github.com/compgenlab/batchq",
"is_deprecated": false,
"latest_version": "v0.4.0",
"repository_url": "https://github.com/compgenlab/batchq",
"versions_count": 17,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": null,
"monthly_downloads": null,
"first_published_at": null,
"latest_published_at": "2026-07-21T01:28:30Z",
"latest_version_yanked": null,
"days_since_latest_publish": 1
}
]
},
"popularity": {
"forks": 0,
"stars": 0,
"watchers": 1,
"fork_history": {
"days": [],
"complete": true,
"collected": 0,
"total_forks": 0
},
"star_history": {
"days": [],
"complete": true,
"collected": 0,
"total_stars": 0
},
"open_issues_and_prs": 0
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [],
"has_llms_txt": false,
"has_dockerfile": true,
"has_mcp_signal": false,
"bootstrap_files": [
"Makefile"
],
"api_schema_files": [],
"has_devcontainer": true,
"typecheck_configs": [],
"toolchain_manifests": [
"go.mod"
],
"largest_source_bytes": 79814,
"source_files_sampled": 109,
"oversized_source_files": 1,
"agent_instruction_files": [
"CLAUDE.md"
],
"agent_instruction_max_bytes": 46907
},
"dependencies": {
"manifests": [
"go.mod"
],
"advisories": {
"error": null,
"scope": "repository_graph",
"source": "osv",
"findings": [
{
"name": "golang.org/x/sys",
"direct": true,
"version": "v0.22.0",
"severity": "unknown",
"ecosystem": "go",
"cvss_score": null,
"advisory_ids": [
"GO-2026-5024"
],
"fixed_version": "0.44.0",
"advisory_count": 1,
"oldest_advisory_days": 60
}
],
"collected": true,
"malicious": [],
"truncated": false,
"by_severity": {
"unknown": 1
},
"advisory_count": 1,
"affected_count": 1,
"assessed_count": 14,
"malicious_count": 0,
"assessed_package": null,
"unassessed_count": 0,
"direct_affected_count": 1
},
"ecosystems": [
"go"
],
"dependencies": [
{
"name": "github.com/spf13/cobra",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.9.1"
},
{
"name": "github.com/BurntSushi/toml",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.6.0"
},
{
"name": "github.com/google/uuid",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.6.0"
},
{
"name": "golang.org/x/sys",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.22.0"
},
{
"name": "modernc.org/sqlite",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.34.5"
}
],
"all_dependencies": {
"error": null,
"source": "github-sbom",
"packages": [
{
"name": "github.com/burntsushi/toml",
"direct": true,
"version": "v1.6.0",
"ecosystem": "go"
},
{
"name": "github.com/google/uuid",
"direct": true,
"version": "v1.6.0",
"ecosystem": "go"
},
{
"name": "github.com/spf13/cobra",
"direct": true,
"version": "v1.9.1",
"ecosystem": "go"
},
{
"name": "golang.org/x/sys",
"direct": true,
"version": "v0.22.0",
"ecosystem": "go"
},
{
"name": "modernc.org/sqlite",
"direct": true,
"version": "v1.34.5",
"ecosystem": "go"
},
{
"name": "github.com/dustin/go-humanize",
"direct": false,
"version": "v1.0.1",
"ecosystem": "go"
},
{
"name": "github.com/inconshreveable/mousetrap",
"direct": false,
"version": "v1.1.0",
"ecosystem": "go"
},
{
"name": "github.com/mattn/go-isatty",
"direct": false,
"version": "v0.0.20",
"ecosystem": "go"
},
{
"name": "github.com/ncruces/go-strftime",
"direct": false,
"version": "v0.1.9",
"ecosystem": "go"
},
{
"name": "github.com/remyoudompheng/bigfft",
"direct": false,
"version": "v0.0.0-20230129092748-24d4a6f8daec",
"ecosystem": "go"
},
{
"name": "github.com/spf13/pflag",
"direct": false,
"version": "v1.0.6",
"ecosystem": "go"
},
{
"name": "modernc.org/libc",
"direct": false,
"version": "v1.55.3",
"ecosystem": "go"
},
{
"name": "modernc.org/mathutil",
"direct": false,
"version": "v1.6.0",
"ecosystem": "go"
},
{
"name": "modernc.org/memory",
"direct": false,
"version": "v1.8.0",
"ecosystem": "go"
}
],
"collected": true,
"truncated": false,
"total_count": 14,
"direct_count": 5,
"indirect_count": 9
}
},
"maintainership": {
"issues": {
"open_prs": 0,
"merged_prs": 58,
"open_issues": 0,
"closed_ratio": 1,
"closed_issues": 1,
"closed_unmerged_prs": 5
},
"bus_factor": 1,
"bot_contributors": 0,
"top_contributors": [
{
"type": "User",
"login": "mbreese",
"commits": 283,
"avatar_url": "https://avatars.githubusercontent.com/u/98979?v=4"
}
],
"contributors_sampled": 1,
"top_contributor_share": 1
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"go.yml"
],
"has_docs_dir": true,
"linter_configs": [],
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [
"go.sum"
],
"scorecard": {
"checks": [
{
"name": "Binary-Artifacts",
"score": 10,
"reason": "no binaries found in the repo",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
},
{
"name": "Branch-Protection",
"score": 0,
"reason": "branch protection not enabled on development/release branches",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": 10,
"reason": "14 out of 14 merged PRs checked by a CI test -- score normalized to 10",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
},
{
"name": "CII-Best-Practices",
"score": 0,
"reason": "no effort to earn an OpenSSF best practices badge detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
},
{
"name": "Code-Review",
"score": 0,
"reason": "Found 0/14 approved changesets -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 10,
"reason": "project has 3 contributing companies or organizations -- score normalized to 10",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": 10,
"reason": "no dangerous workflow patterns detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
},
{
"name": "Dependency-Update-Tool",
"score": 0,
"reason": "no update tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
},
{
"name": "Fuzzing",
"score": 0,
"reason": "project is not fuzzed",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
},
{
"name": "License",
"score": 10,
"reason": "license file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
},
{
"name": "Maintained",
"score": 10,
"reason": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": null,
"reason": "packaging workflow not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 0,
"reason": "dependency not pinned by hash detected -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 0,
"reason": "SAST tool is not run on all commits -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 0,
"reason": "security policy file not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": 0,
"reason": "Project has not signed or included provenance with any releases.",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": 0,
"reason": "detected GitHub workflow tokens with excessive permissions",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 9,
"reason": "1 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "661b9ee06db3f16cd5e39286f60fa902d6c88bce",
"ran_at": "2026-07-22T09:13:18Z",
"aggregate_score": 3.9,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": false,
"has_security_policy": false,
"has_dependabot_config": false
},
"contribution_flow": {
"collected": true,
"ci_last_run_at": "2026-07-21T01:32:14Z",
"oldest_open_prs": [],
"last_merged_pr_at": "2026-07-21T01:28:30Z",
"ci_last_conclusion": "SUCCESS",
"oldest_open_issues": []
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/compgenlab/batchq",
"host": "github.com",
"name": "batchq",
"owner": "compgenlab"
},
"metrics": {
"overall": {
"key": "overall",
"band": "moderate",
"name": "Overall health",
"note": null,
"notes": [],
"value": 57,
"inputs": {
"security": 49,
"vitality": 80,
"community": 24,
"governance": 57,
"engineering": 67
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "good",
"name": "Vitality",
"value": 80,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "good",
"name": "Development activity",
"note": null,
"notes": [],
"value": 74,
"inputs": {
"commits_last_year": 211,
"human_commit_share": 1,
"days_since_last_push": 1,
"active_weeks_last_year": 14
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 1 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "push_recency",
"params": {
"days": 1
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "14/52 weeks with commits",
"points": 9.7,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 14
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "211 commits in the last year",
"points": 18,
"status": "met",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 211
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "excellent",
"name": "Release discipline",
"note": null,
"notes": [],
"value": 90,
"inputs": {
"releases_count": 17,
"latest_release_tag": "v0.4.0",
"releases_from_tags": false,
"days_since_latest_release": 1,
"mean_days_between_releases": 5
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "17 releases published",
"points": 27,
"status": "met",
"details": [
{
"code": "releases_published",
"params": {
"count": 17
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 1 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 1
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~5 days",
"points": 27,
"status": "met",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 5
}
}
],
"max_points": 27
},
{
"key": "openssf_scorecard_signed_releases",
"name": "OpenSSF Scorecard: Signed-Releases",
"detail": "Project has not signed or included provenance with any releases.",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "abandonment",
"band": "excellent",
"name": "Abandonment",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"cap": null,
"state": "maintained",
"guards": [],
"signals": [],
"red_flag": false,
"multiplier_pct": 100,
"declared_reason": null,
"unverified_reason": null,
"unanswered_open_prs": null,
"unanswered_open_issues": null,
"days_since_last_merged_pr": null,
"days_since_last_human_commit": 1,
"days_since_last_human_commit_is_floor": false
},
"components": [
{
"key": "project_is_still_maintained",
"name": "Project is still maintained",
"detail": "last human commit 1 days ago",
"points": 100,
"status": "met",
"details": [
{
"code": "abandonment_maintained",
"params": {
"days": 1
}
}
],
"max_points": 100
}
]
}
],
"description": "Is the project alive — is code being written and are releases shipping?"
},
{
"key": "community",
"band": "critical",
"name": "Community & Adoption",
"value": 24,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "critical",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 1,
"inputs": {
"forks": 0,
"stars": 0,
"watchers": 1,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "0 stars",
"points": 0,
"status": "missed",
"details": [
{
"code": "stars",
"params": {
"count": 0
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "0 forks",
"points": 0,
"status": "missed",
"details": [
{
"code": "forks",
"params": {
"count": 0
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "1 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 1
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "moderate",
"name": "Community health",
"note": null,
"notes": [],
"value": 50,
"inputs": {
"has_readme": true,
"has_license": true,
"has_contributing": false,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 22.5,
"status": "met",
"details": [],
"max_points": 22.5
},
{
"key": "license",
"name": "License",
"detail": "recognized license (MIT)",
"points": 22.5,
"status": "met",
"details": [
{
"code": "license_standard",
"params": {}
},
{
"code": "license_spdx",
"params": {
"spdx": "MIT"
}
}
],
"max_points": 22.5
},
{
"key": "contributing_guide",
"name": "CONTRIBUTING guide",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 18
},
{
"key": "code_of_conduct",
"name": "Code of conduct",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 13.5
},
{
"key": "issue_template",
"name": "Issue template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.2
},
{
"key": "pr_template",
"name": "PR template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.3
}
]
}
],
"description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
},
{
"key": "governance",
"band": "moderate",
"name": "Sustainability & Governance",
"value": 57,
"weight": 0.24,
"metrics": [
{
"key": "maintainer_resilience",
"band": "critical",
"name": "Maintainer resilience (bus factor)",
"note": null,
"notes": [],
"value": 20,
"inputs": {
"bus_factor": 1,
"contributors_sampled": 1,
"top_contributor_share": 1
},
"components": [
{
"key": "bus_factor",
"name": "Bus factor",
"detail": "1 contributor(s) cover half of all commits",
"points": 9,
"status": "partial",
"details": [
{
"code": "bus_factor",
"params": {
"count": 1
}
}
],
"max_points": 54
},
{
"key": "commit_distribution",
"name": "Commit distribution",
"detail": "top contributor authored 100% of commits",
"points": 0,
"status": "missed",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 100
}
}
],
"max_points": 22.5
},
{
"key": "contributor_breadth",
"name": "Contributor breadth",
"detail": "1 contributors",
"points": 1.4,
"status": "partial",
"details": [
{
"code": "contributors_sampled",
"params": {
"count": 1
}
}
],
"max_points": 13.5
},
{
"key": "openssf_scorecard_contributors",
"name": "OpenSSF Scorecard: Contributors",
"detail": "project has 3 contributing companies or organizations -- score normalized to 10",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "responsiveness",
"band": "good",
"name": "Issue & PR responsiveness",
"note": null,
"notes": [],
"value": 82,
"inputs": {
"merged_prs": 58,
"open_issues": 0,
"closed_issues": 1,
"issue_closed_ratio": 1,
"closed_unmerged_prs": 5
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "100% of issues closed",
"points": 46.8,
"status": "met",
"details": [
{
"code": "issues_closed_share",
"params": {
"share": 100
}
}
],
"max_points": 46.75
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "58/63 decided PRs merged",
"points": 35.2,
"status": "partial",
"details": [
{
"code": "decided_prs_merged",
"params": {
"merged": 58,
"decided": 63
}
}
],
"max_points": 38.25
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 0/14 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "at_risk",
"name": "Ownership & stewardship",
"note": null,
"notes": [],
"value": 41,
"inputs": {
"followers": 0,
"owner_type": "Organization",
"is_verified": null,
"owner_login": "compgenlab",
"public_repos": 12,
"account_age_days": 460
},
"components": [
{
"key": "ownership_backing",
"name": "Ownership backing",
"detail": "organization-owned",
"points": 30,
"status": "met",
"details": [
{
"code": "owner_organization",
"params": {}
}
],
"max_points": 30
},
{
"key": "verified_domain",
"name": "Verified domain",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 20
},
{
"key": "owner_reach",
"name": "Owner reach",
"detail": "0 followers of compgenlab",
"points": 0,
"status": "missed",
"details": [
{
"code": "owner_followers",
"params": {
"count": 0,
"login": "compgenlab"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "12 public repos, account ~1 yr old",
"points": 10.6,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 12
}
},
{
"code": "account_age_years",
"params": {
"years": 1
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "excellent",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"packages": [
"github.com/compgenlab/batchq"
],
"ecosystems": "go",
"any_deprecated": false,
"min_days_since_publish": 1
},
"components": [
{
"key": "published_resolvable",
"name": "Published & resolvable",
"detail": "1 package(s) on go",
"points": 25,
"status": "met",
"details": [
{
"code": "packages_published",
"params": {
"count": 1,
"ecosystems": "go"
}
}
],
"max_points": 25
},
{
"key": "publish_recency",
"name": "Publish recency",
"detail": "latest publish 1 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 1
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "17 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 17
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "active, not deprecated or yanked",
"points": 20,
"status": "met",
"details": [
{
"code": "package_not_deprecated",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "moderate",
"name": "Engineering Quality",
"value": 67,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "moderate",
"name": "Engineering practices",
"note": null,
"notes": [],
"value": 68,
"inputs": {
"has_ci": true,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": "1 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 1
}
}
],
"max_points": 24
},
{
"key": "tests_present",
"name": "Tests present",
"detail": null,
"points": 24,
"status": "met",
"details": [],
"max_points": 24
},
{
"key": "linter_config",
"name": "Linter config",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 16
},
{
"key": "pre_commit_hooks",
"name": "Pre-commit hooks",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 9.6
},
{
"key": "editorconfig",
"name": ".editorconfig",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.4
},
{
"key": "openssf_scorecard_ci_tests",
"name": "OpenSSF Scorecard: CI-Tests",
"detail": "14 out of 14 merged PRs checked by a CI test -- score normalized to 10",
"points": 20,
"status": "met",
"details": [],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "moderate",
"name": "Documentation",
"note": null,
"notes": [],
"value": 65,
"inputs": {
"topics": [],
"has_wiki": true,
"homepage": null,
"has_readme": true,
"has_docs_dir": true,
"has_description": false
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 30,
"status": "met",
"details": [],
"max_points": 30
},
{
"key": "documentation_directory",
"name": "Documentation directory",
"detail": null,
"points": 25,
"status": "met",
"details": [],
"max_points": 25
},
{
"key": "documentation_homepage_site",
"name": "Documentation / homepage site",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "repository_description",
"name": "Repository description",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
},
{
"key": "topics",
"name": "Topics",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
},
{
"key": "wiki",
"name": "Wiki",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
}
],
"description": "Are baseline engineering and documentation practices in place?"
},
{
"key": "security",
"band": "at_risk",
"name": "Security",
"value": 49,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "at_risk",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): Packaging. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"packaging"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 39,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 17,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 1,
"scorecard_aggregate": 3.9
},
"components": [
{
"key": "binary_artifacts",
"name": "Binary-Artifacts",
"detail": "no binaries found in the repo",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "branch_protection",
"name": "Branch-Protection",
"detail": "branch protection not enabled on development/release branches",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "14 out of 14 merged PRs checked by a CI test -- score normalized to 10",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "cii_best_practices",
"name": "CII-Best-Practices",
"detail": "no effort to earn an OpenSSF best practices badge detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "code_review",
"name": "Code-Review",
"detail": "Found 0/14 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 3 contributing companies or organizations -- score normalized to 10",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no dangerous workflow patterns detected",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "dependency_update_tool",
"name": "Dependency-Update-Tool",
"detail": "no update tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "fuzzing",
"name": "Fuzzing",
"detail": "project is not fuzzed",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "license",
"name": "License",
"detail": "license file detected",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "maintained",
"name": "Maintained",
"detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow not detected",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "SAST tool is not run on all commits -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file not detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "Project has not signed or included provenance with any releases.",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "token_permissions",
"name": "Token-Permissions",
"detail": "detected GitHub workflow tokens with excessive permissions",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "1 existing vulnerabilities detected",
"points": 6.8,
"status": "partial",
"details": [],
"max_points": 7.5
}
]
},
{
"key": "dependency_advisories",
"band": "excellent",
"name": "Dependency advisories",
"note": "Excluded from scoring (no data or not applicable): Indirect dependencies free of known advisories. Remaining weights renormalized. Matched 14 resolved dependencies against OSV. This repository publishes no package the index resolves, so the repository dependency graph was assessed instead. That graph mixes development and test pins with shipped dependencies, so only the declared runtime dependencies are scored; transitive findings are reported as context and excluded from the score. Reachability is not analyzed.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"indirect_dependencies_free_of_known_advisories"
]
}
},
{
"code": "weights_renormalized",
"params": {}
},
{
"code": "advisories_scope_repository",
"params": {
"assessed": 14
}
},
{
"code": "advisories_repo_graph_caveat",
"params": {}
},
{
"code": "advisories_reachability",
"params": {}
}
],
"value": 89,
"inputs": {
"source": "osv",
"advisories": 1,
"affected_packages": 1,
"assessed_packages": 14,
"unassessed_packages": 0,
"affected_by_severity": "unknown 1",
"direct_affected_packages": 1
},
"components": [
{
"key": "direct_dependencies_free_of_known_advisories",
"name": "Direct dependencies free of known advisories",
"detail": "1 affected: golang.org/x/sys v0.22.0 (unknown)",
"points": 26.6,
"status": "partial",
"details": [
{
"code": "advisories_affected",
"params": {
"count": 1,
"packages": "golang.org/x/sys v0.22.0 (unknown)"
}
}
],
"max_points": 35
},
{
"key": "indirect_dependencies_free_of_known_advisories",
"name": "Indirect dependencies free of known advisories",
"detail": "transitive set not separable from development and test dependencies in this scope",
"points": 0,
"status": "excluded",
"details": [
{
"code": "advisories_scope_not_separable",
"params": {}
}
],
"max_points": 25
},
{
"key": "no_advisories_left_outstanding",
"name": "No advisories left outstanding",
"detail": "no advisory has been public longer than 90 days",
"points": 40,
"status": "met",
"details": [
{
"code": "advisories_none_stale",
"params": {
"days": 90
}
}
],
"max_points": 40
}
]
},
{
"key": "malicious_dependencies",
"band": "excellent",
"name": "Malicious dependencies",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"source": "osv",
"meaning": "reported as a malicious package by the OpenSSF corpus; the remedy is removal or moving off the compromised name, never an upgrade of the same artifact. Versions the registry has since pulled are listed but not scored",
"packages": [],
"red_flag": false,
"assessed_packages": 14,
"malicious_packages": 0,
"direct_malicious_packages": 0,
"withdrawn_malicious_packages": 0,
"installable_malicious_packages": 0
},
"components": [
{
"key": "no_dependency_reported_as_a_malicious_package",
"name": "No dependency reported as a malicious package",
"detail": "no dependency is reported as a malicious package",
"points": 100,
"status": "met",
"details": [
{
"code": "no_malicious_dependencies",
"params": {}
}
],
"max_points": 100
}
]
},
{
"key": "high_risk_jurisdiction_exposure",
"band": "excellent",
"name": "High-Risk Jurisdiction Exposure",
"note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
"notes": [
{
"code": "jurisdiction_evidence_limits",
"params": {}
}
],
"value": 100,
"inputs": {
"meaning": "self-published location evidence; not nationality or citizenship",
"red_flag": false,
"exposures": [],
"policy_countries": [
"Russia",
"Iran",
"North Korea"
],
"review_only_matches": 0,
"assessed_self_published_locations": 2
},
"components": [
{
"key": "policy_exposure_multiplier",
"name": "Policy exposure multiplier",
"detail": "no confirmed policy-scope location match",
"points": 100,
"status": "met",
"details": [
{
"code": "jurisdiction_no_match",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
},
{
"key": "ai_readiness",
"band": "good",
"name": "AI Readiness",
"value": 81,
"weight": 0,
"metrics": [
{
"key": "ai_agent_context",
"band": "excellent",
"name": "Agent context & guidance",
"note": null,
"notes": [],
"value": 85,
"inputs": {
"has_llms_txt": false,
"legible_history_share": 1,
"agent_instruction_files": [
"CLAUDE.md"
],
"agent_instruction_max_bytes": 46907
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": "CLAUDE.md",
"points": 45,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "CLAUDE.md"
}
}
],
"max_points": 45
},
{
"key": "machine_readable_docs_llms_txt",
"name": "Machine-readable docs (llms.txt)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "legible_commit_history",
"name": "Legible commit history",
"detail": "100 of 100 human commits state their intent (structured subject or explanatory body)",
"points": 40,
"status": "met",
"details": [
{
"code": "legible_history",
"params": {
"legible": 100,
"sampled": 100
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "good",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 71,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [
"go.sum"
],
"has_dockerfile": true,
"typed_language": true,
"bootstrap_files": [
"Makefile"
],
"has_devcontainer": true,
"has_linter_config": false,
"typecheck_configs": [],
"agent_commit_share": 0.62,
"toolchain_manifests": [
"go.mod"
],
"dependency_bot_commit_share": 0
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": "Makefile",
"points": 18,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "Makefile"
}
}
],
"max_points": 18
},
{
"key": "automated_tests",
"name": "Automated tests",
"detail": null,
"points": 22,
"status": "met",
"details": [],
"max_points": 22
},
{
"key": "lint_format_config",
"name": "Lint / format config",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 11
},
{
"key": "static_type_checking",
"name": "Static type checking",
"detail": "Go (statically typed)",
"points": 11,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "Go"
}
}
],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": "devcontainer, Dockerfile, lockfile",
"points": 10,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "devcontainer, Dockerfile, lockfile"
}
}
],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "62 of the last 100 commits agent-authored or agent-credited",
"points": 10,
"status": "met",
"details": [
{
"code": "agent_authored_commits",
"params": {
"count": 62,
"sampled": 100
}
}
],
"max_points": 10
},
{
"key": "automated_maintenance",
"name": "Automated maintenance",
"detail": "no automated dependency updates observed",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_dependency_automation",
"params": {}
}
],
"max_points": 8
},
{
"key": "openssf_scorecard_pinned_dependencies",
"name": "OpenSSF Scorecard: Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "excellent",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"primary_language": "Go",
"largest_source_bytes": 79814,
"source_files_sampled": 109,
"oversized_source_files": 1
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "Go (statically typed)",
"points": 45,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "Go"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "1/109 source files over 60KB",
"points": 54.5,
"status": "partial",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 109,
"oversized": 1
}
}
],
"max_points": 55
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
}
],
"metrics_version": "1.13.0"
},
"warnings": [],
"report_type": "repository",
"generated_at": "2026-07-22T09:13:34.334261Z",
"schema_version": "0.26.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/c/compgenlab/batchq.svg",
"full_name": "compgenlab/batchq",
"license_state": "standard",
"license_spdx": "MIT"
}