Skip to content

Bind AgentCTL jobs to declared project environments - #15

Merged
Sinity merged 4 commits into
masterfrom
feature/agentctl/environment-final-correction
Aug 25, 2026
Merged

Bind AgentCTL jobs to declared project environments#15
Sinity merged 4 commits into
masterfrom
feature/agentctl/environment-final-correction

Conversation

@Sinity

@Sinity Sinity commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Summary

  • bind AgentCTL jobs to each project's declared checkout environment
  • fail before worker execution when project preflight is missing, stale, malformed, or times out
  • gate every system activation route on complete configured-project rollout

Problem

AgentCTL workers could enter an assigned checkout without the command environment required by that project. Polylogue workers repeatedly had to rediscover the virtual environment and verification entrypoint, while an incautious worker could bypass the mandated harness. A partial runtime rollout would have made affected projects refuse dispatch only after activation.

Solution

Project descriptors now declare a bounded preflight executed through the checkout-bound project environment. Attested jobs use a strict versioned input contract, clear ambient language-runtime overrides, and surface effective environment capability. Switch, boot, test-system, and rendered command entrypoints all evaluate the configured-root completeness gate before activation. Stale private records fail closed without changing ordinary declared operations.

Verification

  • AgentCTL exact-head lint operation succeeded, receipt 7dc52ef0-c71f-4c16-9165-1f381449bb59
  • Sinnixd package suite: 282 passed, 1 skipped
  • rendered environment gate and Sinnixd builds succeeded
  • both maintained lint routes succeeded
  • mutation checks rejected removed boot gating and reordered switch gating
  • external descriptor prerequisites landed in Polylogue PR #4148, Sinex PR #2648, and Lynchpin PR fix(home-manager): avoid agent directory collision #6

No NixOS switch, boot activation, or service restart was performed by this PR.

@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c7fdd447-b5e2-440e-941c-4cf1766c2edd


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

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

@Sinity
Sinity merged commit ada3352 into master Aug 25, 2026
2 of 4 checks passed
@Sinity
Sinity deleted the feature/agentctl/environment-final-correction branch August 25, 2026 17:38

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a631197612

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +168 to +173
preflight = subprocess.run(
preflight_command,
cwd=checkout,
check=False,
timeout=AGENT_PREFLIGHT_TIMEOUT_SECONDS,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Remove the private prompt when preflight fails

When the declared preflight exits nonzero, times out, or cannot be executed, _run_agent raises before reaching the later try/finally that unlinks prompt_path. The contract input has already been deleted by main, so each such terminal job leaves its raw, potentially sensitive prompt indefinitely under the state directory; wrap the preflight and backend execution in the same cleanup scope.

Useful? React with 👍 / 👎.

Comment on lines +138 to +141
if not project.environment.preflight:
raise ContractError(
f"project {project_id} does not declare an agent environment preflight"
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Enforce the published agent-capable flag on launch

For a descriptor without [workspace] but with an optional non-empty environment.preflight, the catalog publishes agent_capable = false and the activation audit skips it, yet this check passes and start_agent proceeds because ProjectCatalog.checkout does not require a workspace policy. This makes the advertised capability unreliable and permits launches through a project that the new contract classifies as non-agent-capable; reject not project.agent_capable here as well.

Useful? React with 👍 / 👎.

Comment on lines +117 to +122
${pkgs.nix}/bin/nix eval \
"$_flake_dir#nixosConfigurations.sinnix-prime.config.sinnix.services.sinnixd.projectRoots" \
--json \
--impure \
"''${nix_override_args[@]}" \
| ${pkgs.jq}/bin/jq -r '.[]'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid the duplicate activation evaluation

Every gated switch, boot, and test-system invocation now performs this separate impure evaluation of the NixOS configuration before nh evaluates the same configuration for the rebuild. Besides duplicating an expensive evaluation and creating another failure/divergence boundary, this directly violates the repository requirement not to preflight a switch with a duplicate evaluation; integrate the contract into the rebuild evaluation or obtain the roots without evaluating nixosConfigurations a second time.

AGENTS.md reference: AGENTS.md:L203-L205

Useful? React with 👍 / 👎.

project = raw.get("project")
if isinstance(project, Mapping) and isinstance(project.get("id"), str):
project_name = project["id"]
adapter = load_project_adapter(root)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reject duplicate project IDs in the activation gate

When two configured roots declare the same project.id, this loop validates each adapter independently and can let the gate pass, even though ProjectCatalog.__init__ rejects the same roots as duplicate IDs when the newly activated daemon starts. Thus a configuration accepted by the pre-activation gate can leave sinnixd unable to start; collect the loaded adapters and apply the same cross-root uniqueness check before succeeding.

AGENTS.md reference: AGENTS.md:L141-L142

Useful? React with 👍 / 👎.

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.

1 participant