Skip to content

fix(backend): stop routine tasks from getting office skills they can't run - #3502

Merged
carlosflorencio merged 3 commits into
kdlbs:mainfrom
nova28:fix/routine-office-skills-gate
Sep 9, 2026
Merged

fix(backend): stop routine tasks from getting office skills they can't run#3502
carlosflorencio merged 3 commits into
kdlbs:mainfrom
nova28:fix/routine-office-skills-gate

Conversation

@nova28

@nova28 nova28 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Tip

PR walkthrough: Open the visual walkthrough

Heavy Office routine tasks launch through the same kanban path as an ordinary task rather than the Office scheduler path, so they never receive KANDEV_CLI in their environment — yet they still received the bundled Office skills, every one of which shells out to $KANDEV_CLI. This change stops deploying those system skills to a launch whose finalized environment doesn't actually carry Office runtime env.

Today: A heavy (task_template) Office routine's agent still gets the bundled kandev-task-ops and kandev-approvals skills, because they're written per-workspace and were never gated on how the task launched. The first office-skill command the agent tries expands to a bare kandev ... with no CLI on the PATH and fails.
After this: Bundled system skills are only deployed when the launch's finalized environment actually carries KANDEV_CLI — the same signal the Office scheduler path always sets. A routine-task agent simply doesn't receive skills it can't execute. User-authored skills (is_system = false) are unaffected.
Who hits this: Any workspace running heavy Office routines; today every one of those agents hits a guaranteed failure on its first office-skill invocation.
Scope: standalone — narrow, single-purpose fix, no sibling PRs.
Not here: making routine tasks IsFromOffice (rejected — that flag gates ~20 other behaviours, including a hard launch refusal in task_operations.go); injecting KANDEV_CLI alone (rejected — other required Office env vars, e.g. KANDEV_API_KEY, would still be missing, trading a clear absence for an auth failure instead).

Important Changes

  • skill.Skill gains IsSystem bool, threaded from config (office/skills/runtime_adapter.go) through to the deploy request.
  • skill.Request.OfficeRuntime bool — set from whether KANDEV_CLI is present in the finalized launch env (skill_deploy.go, at the point the env is already resolved) — gates IsSystem skills out of the manifest (skill/manifest.go) when false.

Known trade-off: the gate keys on KANDEV_CLI being present in the finalized launch env. An install with agentctlBinaryPath unset (office/service/env_builder.go:33) never sets KANDEV_CLI, even for a genuine Office launch, so it would also stop receiving Office system skills. That's a mis-configured install, and a silently-absent skill is preferable to one guaranteed to fail — but it's a real trade-off, called out here rather than left implicit.

Known gap (Kubernetes executor): on the k8s executor this gate is blunted by a pre-existing bug in executor_kubernetes_files.go — it has no cleanKandevSkills equivalent, so system skills already materialized on a retained PVC survive a manifest that now omits them. That bug is pre-existing, outside this diff, and tracked separately.

Validation

  • go build -tags fts5 ./... — build OK; go vet ./... — OK.
  • go test -tags fts5 -count=1 ./internal/agent/runtime/lifecycle/skill/... ./internal/office/skills/... ./internal/office/configloader/... — all ok.
  • golangci-lint run ./... (make -C apps/backend lint) — 0 issues.
  • make -C apps/backend test (full suite) — fails on the same pre-existing, environment-dependent packages as a scratch worktree built from this PR's merge base (temp-dir path length limits, unavailable NATS/turn-table test doubles, etc.); none of the failing packages exercise this diff. Two packages that failed only under full-suite contention (internal/common/subproc, internal/github) pass cleanly run in isolation.
  • make typecheck, make lint, make lint-format, cd apps/web && pnpm run i18n:ratchet — all clean. (lint-harness fails locally on a pre-existing Python 3.9-vs-3.10 syntax issue in .github/scripts/lint-harness-files.py, unrelated to and unchanged by this diff.)
  • No apps/web files changed, so Playwright e2e was not required for this change.

Possible Improvements

Low risk. Coverage gap noted in review: no test currently spans the Office scheduler → lifecycle boundary, or exercises a prior-system-skills → gated transition end-to-end; this PR's tests cover the gate itself at the deploy-request/manifest level.

Checklist

  • If I do not have repository write access and this is a large architectural change, I discussed the direction in a linked issue before opening this PR.
  • This PR contains one logical change; unrelated work is split into separate PRs.
  • I have performed a self-review of my code.
  • I have manually tested my changes and they work as expected.
  • My changes have tests that cover the new functionality and edge cases.
  • If my change touches UI files (apps/web/), I have added or updated Playwright e2e tests in apps/web/e2e/ and verified them with make test-e2e.
  • I checked whether this affects public docs in docs/public/** and updated them or noted why no docs change is needed. (Backend-internal skill deployment behavior; no public docs reference this gate.)

Review in cubic

…ime env

A heavy-routine task launches on the kanban path (IsFromOffice=false by
design), which never sets KANDEV_CLI or the other office runtime vars —
but skill deploy is keyed on the agent profile, not on office-ness, so
the routine agent's worktree still got the bundled office skills
(kandev-protocol, kandev-task-ops, ...) whose instructions all assume
those vars are set. Every command they told the agent to run failed.

Gate deployment of is_system skills on the launch's finalized env
actually carrying KANDEV_CLI (skill.Request/SkillDeployRequest.OfficeRuntime),
derived once in runSkillDeploy from the finalized launch env. User-authored
skills are unaffected.
@nova28
nova28 temporarily deployed to opencode-review-trusted September 8, 2026 11:45 — with GitHub Actions Inactive
@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Advanced

Run ID: 2e93567b-abbf-42e8-9416-28ab1678764e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Advanced

Run ID: 699afb4e-87ae-4a1e-8db9-aa170430cea7

📥 Commits

Reviewing files that changed from the base of the PR and between 18d38c1 and 0a2df79.

📒 Files selected for processing (9)
  • apps/backend/internal/agent/runtime/lifecycle/skill/deployer.go
  • apps/backend/internal/agent/runtime/lifecycle/skill/deployer_officeruntime_test.go
  • apps/backend/internal/agent/runtime/lifecycle/skill/manifest.go
  • apps/backend/internal/agent/runtime/lifecycle/skill/types.go
  • apps/backend/internal/agent/runtime/lifecycle/skill_deploy.go
  • apps/backend/internal/agent/runtime/lifecycle/skill_deploy_test.go
  • apps/backend/internal/agent/runtime/lifecycle/skill_deployer.go
  • apps/backend/internal/agent/runtime/lifecycle/skill_deployer_adapter.go
  • apps/backend/internal/office/skills/runtime_adapter.go

Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review.


📝 Summary

Summary by CodeRabbit

  • Bug Fixes
    • System skills are now deployed only when the Office runtime is available, preventing unsupported skills from being included in other launch environments.
    • User-authored skills continue to deploy regardless of Office runtime availability.
    • Office runtime detection now reflects the finalized launch environment.

Walkthrough

The deployment flow derives Office runtime availability from KANDEV_CLI, forwards it through lifecycle adapters, and uses it to exclude bundled system skills from manifests when the runtime is unavailable. Tests cover both propagation and manifest behavior.

Changes

Office runtime skill gating

Layer / File(s) Summary
Propagate Office runtime state
apps/backend/internal/agent/runtime/lifecycle/skill_deploy.go, apps/backend/internal/agent/runtime/lifecycle/skill_deployer.go, apps/backend/internal/agent/runtime/lifecycle/skill_deployer_adapter.go, apps/backend/internal/agent/runtime/lifecycle/skill/deployer.go, apps/backend/internal/agent/runtime/lifecycle/skill_deploy_test.go
The deployment path derives OfficeRuntime from KANDEV_CLI and forwards it to the runtime-tier deployer. Tests cover both environment states.
Gate system skills in manifests
apps/backend/internal/agent/runtime/lifecycle/skill/types.go, apps/backend/internal/office/skills/runtime_adapter.go, apps/backend/internal/agent/runtime/lifecycle/skill/manifest.go, apps/backend/internal/agent/runtime/lifecycle/skill/deployer_officeruntime_test.go
Runtime skills preserve IsSystem metadata. Manifest construction skips system skills without Office runtime variables and retains user-authored skills. Regression tests cover enabled and disabled runtime states.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 0a2df

System Office skills are now omitted when the Office CLI runtime is unavailable, while user-authored skills remain deployed. The runtime signal and manifest behavior are covered by targeted tests, with no concrete current-head merge-blocking risk identified.

Sequence Diagram(s)

sequenceDiagram
  participant PreparedLaunch
  participant runSkillDeploy
  participant skillDeployerAdapter
  participant RuntimeDeployer
  participant ManifestBuilder
  PreparedLaunch->>runSkillDeploy: Read KANDEV_CLI
  runSkillDeploy->>skillDeployerAdapter: Set OfficeRuntime
  skillDeployerAdapter->>RuntimeDeployer: Forward OfficeRuntime
  RuntimeDeployer->>ManifestBuilder: Build manifest with OfficeRuntime
  ManifestBuilder->>ManifestBuilder: Skip system skills when false
Loading

Suggested reviewers: carlosflorencio

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the primary fix: routine tasks no longer receive Office skills that require unavailable runtime support.
Description check ✅ Passed The description is complete and directly aligned with the change. It explains the problem, implementation, scope, trade-offs, known gaps, validation results, and checklist status.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 9 files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit checks the launch-time air
Runtime flags guide skills with care
System skills wait when variables hide
User skills remain inside
Tests guard each deployment path
Clear manifests mark the path

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Sep 8, 2026

Copy link
Copy Markdown

Greptile Summary

This PR threads the system-skill classification into runtime deployment and omits bundled Office skills when the finalized launch environment does not appear to support them.

  • Adds IsSystem to the runtime skill representation and propagates it through the Office adapter.
  • Adds an OfficeRuntime deployment signal and filters system skills while preserving user-authored skills.
  • Adds regression coverage at the environment-to-request and manifest/deployment boundaries.
  • The current signal is too weak because independently configured KANDEV_CLI does not establish the complete Office runtime contract.

Confidence Score: 4/5

The PR should not merge until the deployment gate verifies the complete Office runtime contract instead of trusting a potentially independent KANDEV_CLI value.

Executor profiles can supply KANDEV_CLI to ordinary tasks without supplying the API credentials and runtime identity required by bundled Office skills, causing the new gate to deploy skills that still cannot run.

Files Needing Attention: apps/backend/internal/agent/runtime/lifecycle/skill_deploy.go

Important Files Changed

Filename Overview
apps/backend/internal/agent/runtime/lifecycle/skill_deploy.go Derives the new deployment gate from only KANDEV_CLI, allowing incomplete non-Office environments to pass.
apps/backend/internal/agent/runtime/lifecycle/skill/manifest.go Filters classified system skills from manifests when the supplied Office runtime signal is false.
apps/backend/internal/agent/runtime/lifecycle/skill/types.go Adds the system-skill classification to the runtime skill model.
apps/backend/internal/office/skills/runtime_adapter.go Correctly propagates the persisted IsSystem classification into the runtime model.
apps/backend/internal/agent/runtime/lifecycle/skill/deployer_officeruntime_test.go Covers manifest delivery for system and user-authored skills in both gate states, but assumes the boolean itself represents a complete Office environment.
apps/backend/internal/agent/runtime/lifecycle/skill_deploy_test.go Covers derivation from presence or absence of KANDEV_CLI but does not exercise an incomplete environment containing only that variable.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A[Finalized launch environment] --> B{KANDEV_CLI non-empty?}
    B -- No --> C[Omit system skills]
    B -- Yes --> D[Deploy system skills]
    D --> E[Skills invoke Office CLI]
    E --> F{API credentials and runtime identity present?}
    F -- Yes --> G[Office operations run]
    F -- No --> H[CLI operations fail]
Loading

Reviews (1): Last reviewed commit: "fix(backend): stop deploying office syst..." | Re-trigger Greptile

Comment thread apps/backend/internal/agent/runtime/lifecycle/skill_deploy.go Outdated
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Claude finished @nova28's task in 5m 31s —— View job


Findings

Suggestion (recommended, doesn't block)

  1. OfficeRuntime docstring implies a multi-variable check that isn't thereskill_deployer.go:35-38, skill/deployer.go:88-92

    • Issue: Both field comments say "Office runtime variables (KANDEV_CLI, KANDEV_API_KEY, ...)" with an ellipsis, which reads as a compound gate. The actual derivation at skill_deploy.go:47 checks only KANDEV_CLI != "". Future maintainers reading the field contract will infer stronger guarantees than exist.
    • Why: A reader who extends the gate (e.g. to also check KANDEV_API_KEY) will assume the comment is already accurate and may miss that only one key is actually tested today.
    • Fix: Make the comment explicit about the single-key check and document that other vars are assumed to be co-present when KANDEV_CLI is set by the Office scheduler path (posted as an inline comment above).
  2. Profile-contributed KANDEV_CLI can produce a false-positive OfficeRuntimeskill_deploy.go:47

    • (Note: greptile already filed a variant of this finding at skill_deploy.go:47. The mechanism below is additional technical detail.)
    • Issue: buildEnvForExecution calls mergeAgentProfileEnvFromInfomergeEnvFillMissing (profile_env.go:47–57) before runSkillDeploy reads prepared.Env["KANDEV_CLI"]. mergeEnvFillMissing fills any key that is absent in the destination map. A user-configured profile env var {Key: "KANDEV_CLI", Value: "/some/path"} on a non-Office agent profile will therefore survive into the finalized env unblocked — KANDEV_CLI != "" becomes true, OfficeRuntime flips to true, and system skills are deployed to a task that has no KANDEV_API_KEY, KANDEV_RUN_TOKEN, or KANDEV_RUN_ID. The result is auth failure on the first skill invocation rather than "command not found," which is slightly better than the original bug but not the clean absence the fix intends.
    • Why: Low practical risk — a user would have to deliberately add KANDEV_CLI to their agent profile's env vars. The PR description calls out the analogous false-negative (empty agentctlBinaryPath) as a known trade-off; this is the symmetric false-positive direction that isn't mentioned.
    • Fix (if desired): Tighten the gate by also requiring KANDEV_API_KEY != "" or KANDEV_RUN_ID != "", which are Office-exclusive and not in any agent profile's normal env var set. A short comment in runSkillDeploy calling out this false-positive surface would serve future readers even without changing the check.

Summary

Severity Count
Blocker 0
Suggestion 2

Verdict: Ready to merge with suggestions.

The core mechanism is sound: KANDEV_CLI is an effective discriminator between Office scheduler launches and kanban/routine launches in the common case, the gate is checked against the fully-finalized env (after profile env var merging), and the fix correctly eliminates the guaranteed "CLI not found" failure for heavy routine tasks. The Kubernetes PVC gap is pre-existing and noted in the PR. Both suggestions above are low-risk; the docstring inaccuracy (suggestion 1) is the one worth addressing before merge to keep the field contract honest.

Comment thread apps/backend/internal/agent/runtime/lifecycle/skill_deployer.go Outdated
@carlosflorencio
carlosflorencio self-requested a review September 8, 2026 18:51
@carlosflorencio
carlosflorencio temporarily deployed to opencode-review-trusted September 8, 2026 19:16 — with GitHub Actions Inactive
@carlosflorencio

Copy link
Copy Markdown
Member

Thanks for the contribution. We pushed 3b7e821 to tighten the system-skill gate: Office skills now deploy only when the backend marks the launch as Office mode and a usable KANDEV_CLI is present. This prevents executor-profile environment values from enabling Office-only skills on regular tasks. We also added lifecycle and adapter regression coverage.

@carlosflorencio
carlosflorencio temporarily deployed to opencode-review-trusted September 8, 2026 21:36 — with GitHub Actions Inactive
@carlosflorencio

Copy link
Copy Markdown
Member

CI fix: updated the launch-context regression to create and assign a real Office task. This keeps the test aligned with the Office-only runtime gate and prevents normal Kanban tasks from being treated as Office sessions.

@carlosflorencio
carlosflorencio merged commit fc1fc3a into kdlbs:main Sep 9, 2026
72 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants