Skip to content

feat(admin): add stopped status to KiloClaw instances view#1458

Merged
jeanduplessis merged 2 commits intomainfrom
kiloclaw-admin-status
Mar 24, 2026
Merged

feat(admin): add stopped status to KiloClaw instances view#1458
jeanduplessis merged 2 commits intomainfrom
kiloclaw-admin-status

Conversation

@jeanduplessis
Copy link
Contributor

@jeanduplessis jeanduplessis commented Mar 24, 2026

Summary

Problem

The KiloClaw admin dashboard at /admin/kiloclaw only showed two instance states: Active and Destroyed. When the billing lifecycle cron stops a machine (trial expiry, subscription cancellation, past-due), the instance enters an invisible limbo — still marked "active" in the DB but with its machine stopped and subscription suspended. Admins had no way to distinguish these from truly running instances.

Solution

  • Joined kiloclaw_subscriptions in the admin list, get, and stats endpoints to surface suspended_at alongside instance data.
  • Added a tri-state status badge: Active (green), Suspended (amber), Destroyed (grey) — derived from destroyed_at and suspended_at.
  • Added a "Suspended Only" filter option to the status dropdown.
  • Added a "Suspended Instances" stats card to the overview dashboard.
  • Narrowed the "Active" filter/count to exclude suspended instances (destroyed_at IS NULL AND suspended_at IS NULL).
  • Architecture: No schema migration needed — suspended_at already exists on kiloclaw_subscriptions with a unique constraint on user_id, making the LEFT JOIN 1:1 and safe.

Why this approach

The alternative was adding an explicit status column to kiloclaw_instances, but that would require a migration, backfill, and keeping it in sync with the billing lifecycle cron that already manages suspended_at on the subscription table. Deriving the state from a JOIN avoids data duplication and is consistent with how the billing system already models suspension.

Verification

  • pnpm typecheck — passed (all 30 workspace projects)
  • pnpm lint (via pre-commit hook) — passed
  • pnpm format:check (via pre-commit hook) — passed
  • Six-agent code review (security, types, logic, data, resources, style) — 0 findings

Visual Changes

All changes are on the /admin/kiloclaw page:

Overview stats cards (top of page)

  • Previously: 4-card grid — Total Instances, Active Instances, Unique Users, Avg Lifespan.
  • Now: 5-card grid — Total Instances, Active Instances, Suspended Instances (new), Unique Users, Avg Lifespan.
  • The new "Suspended Instances" card shows the count of instances where suspended_at IS NOT NULL and subtitle "Suspended by billing lifecycle".
  • The "Active Instances" count now excludes suspended instances (previously it included them).

Status filter dropdown

  • Previously: All Instances, Active Only, Destroyed Only.
  • Now: All Instances, Active Only, Suspended Only (new), Destroyed Only.

Instance table status badge

  • Previously: binary — green "Active" badge or grey "Destroyed" badge.
  • Now: tri-state — green "Active", amber "Suspended" (new), or grey "Destroyed".
  • An instance shows "Suspended" when destroyed_at is null but the subscription's suspended_at is set (billing lifecycle has stopped the machine).

Reviewer Notes

  • The kiloclaw_subscriptions.user_id column has a UNIQUE constraint, so the LEFT JOIN cannot produce duplicate rows. If the future multi-instance-per-user model changes this, the join will need to be updated.
  • Instances without a subscription row get suspended_at = null from the LEFT JOIN, correctly mapping to "Active" status.
  • The active filter now excludes suspended instances — this is a behavioral change for anyone relying on the "Active Only" filter to include suspended instances.

Join kiloclaw_subscriptions to surface suspended_at in the admin
instance list, enabling a tri-state status: Active, Stopped, Destroyed.

- Add stopped filter option and amber badge in instance table
- Add Stopped Instances stats card to overview dashboard
- Update active filter to exclude suspended instances
@kilo-code-bot
Copy link
Contributor

kilo-code-bot bot commented Mar 24, 2026

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0

Fix these issues in Kilo Cloud

Issue Details (click to expand)

WARNING

File Line Issue
src/routers/admin-kiloclaw-instances-router.ts 32 Renaming the filter literal to suspended breaks existing ?status=stopped URLs because the page still forwards raw query-string values into the tRPC request.
Other Observations (not in diff)

N/A

Files Reviewed (2 files)
  • src/app/admin/components/KiloclawInstances/KiloclawInstancesPage.tsx - 0 issues
  • src/routers/admin-kiloclaw-instances-router.ts - 1 issue

Reviewed by gpt-5.4-20260305 · 357,812 tokens

Copy link
Contributor

@pandemicsyn pandemicsyn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, one question in line, but good to go either way.

Aligns the UI terminology with the underlying suspended_at field and
avoids confusion with the machine-level 'stopped' worker state.
@jeanduplessis jeanduplessis merged commit 1f4a5a1 into main Mar 24, 2026
19 checks passed
@jeanduplessis jeanduplessis deleted the kiloclaw-admin-status branch March 24, 2026 13:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants