Skip to content

docs(rfc-0034): add status query design, progress visibility, and opencode comparison - #249

Open
Million-mo wants to merge 1 commit into
wolf1069b:mainfrom
Million-mo:docs/rfc-0034-status-query-design
Open

docs(rfc-0034): add status query design, progress visibility, and opencode comparison#249
Million-mo wants to merge 1 commit into
wolf1069b:mainfrom
Million-mo:docs/rfc-0034-status-query-design

Conversation

@Million-mo

Copy link
Copy Markdown
Collaborator

Summary

Advances RFC-0034 (BackgroundTask Architecture Redesign) from DRAFT to REVIEW by adding three major design sections that were missing from the original proposal.

What Changed

1. Cross-System Comparison with opencode (Section 2.5)

Conducted a comparative analysis of opencode's background task system (/Users/mollion-mo/Downloads/projects/opencode). Key findings documented:

  • opencode exposes a single task tool with optional background parameter — no task_status, background_output, or background_cancel tools
  • A test in registry.test.ts:103-110 explicitly asserts that task_status does not exist, confirming deliberate design choice
  • opencode's LLM sees only two state transitions (launch → completion); intermediate status is invisible
  • opencode's BackgroundJob.Service has internal get()/list() for system-level status, but not exposed as LLM tools
  • Comparison matrix across 7 dimensions (status query, progress, notification, cancel, steering, polling guidance, states)

Key takeaway: opencode's "no status query" design works for short research tasks (~30s–5min). xeno-agent's industrial diagnosis involves 5–10min tasks where blind cancellation is expensive, and steer_task (which opencode lacks) requires status information for informed intervention.

2. Status Query & Progress Design (Section 7.4 + Q5 Decision)

Added Q5 design decision: How should running-task status and progress be exposed to the LLM?

Three options evaluated:

  • A: opencode-style (no status tool) — rejected: makes steer_task blind
  • B: Status + progress with norms — selected
  • C: Status only, no progress — rejected: less useful, may tempt repeated polling

task_status() tool returns a structured dict with 10 typed fields including:

  • status, duration, created_at, started_at, completed_at
  • progress_preview: tail (~500 chars) of output_file for running tasks — the data already exists (_run_and_stream incrementally writes via fs.pipe()), just not exposed
  • error for failed tasks

list_tasks() companion tool: Returns a markdown table of all session tasks, addressing the "lost task ID in long conversations" problem.

3. Multi-Layer Norm Constraint Design (Section 7.5)

The status query capability is technically available but constrained through four defense-in-depth layers:

Layer What It Prevents Mechanism
Tool description Unaware misuse YAML schema text scoping use to stuck-detection/steering
Parameter design Conflating status with result Separate task_status and task_result tools
Runtime soft-limit Sustained polling loops Warning injected after N calls per task in M seconds
System prompt All forms of polling Explicit "wait for notification" directive

No single layer is sufficient. Together they create a gradient from "LLM knows it shouldn't poll" to "system actively warns when polling is detected."

4. Additional Changes

  • Problems 6-7 (Section 3.1): Documents progress opacity (output_file written but not exposed) and task listing gap
  • Goals 7-8 (Section 4.1): Status query with progress visibility + multi-layer norm constraint
  • Section 8.2: Expanded task_status(), steer_task(), list_tasks() API signatures with detailed docstrings
  • Open Questions 6-9: progress_preview char limit, soft-limit configurability, list_tasks placement, binary output handling
  • Decision D5 recorded in Decision Record
  • Status: DRAFT → REVIEW

Motivation

RFC-0034 was created on 2026-06-09 but stalled in DRAFT — no PR or issue was associated with it, so the design never received review attention. This PR advances the RFC to REVIEW and surfaces the status query design question that emerged from comparing xeno-agent's capabilities with opencode's approach.

The core question: should the parent agent be able to query the status of a running background task? opencode says no (and enforces it with a test). xeno-agent's industrial diagnosis use case — with steer_task and expensive long-running tasks — says yes, but with constraints. This RFC amendment documents that decision with evidence and design.

Related

  • Original RFC: packages/agentpool/docs/rfcs/RFC-0034-background-task-redesign.md
  • xeno-agent RFC: packages/xeno-agent/docs/rfcs/RFC-0001-async-task-background-task-v2.md
  • Current implementation: packages/xeno-agent/src/xeno_agent/agentpool/capabilities/background_task_capability.py

Checklist

  • RFC status advanced from DRAFT to REVIEW
  • All required sections complete (per RFC skill checklist)
  • At least 2 alternatives analyzed (Q5: 3 options evaluated)
  • Evaluation criteria explicit and measurable
  • Trade-offs documented for each option
  • Language is objective and evidence-based
  • Open questions clearly listed (9 total)
  • Implementation plan realistic (unchanged from original RFC)

🤖 Generated with Claude Code

…ncode comparison

Add three major sections to RFC-0034 based on cross-system analysis:

1. Section 2.5: Cross-System Comparison with opencode
   - Documents opencode's single-tool, no-status-query approach
   - Comparison matrix across 7 dimensions
   - Key takeaway: opencode's design suits short tasks; xeno-agent's
     industrial diagnosis needs status visibility for steering decisions

2. Problems 6-7 (Section 3.1): Progress opacity and task listing gaps
   - output_file is incrementally written but not exposed in non-block mode
   - No tool to list all active tasks (lost task IDs in long conversations)

3. Q5 Decision (Section 6): Status + progress with multi-layer norms
   - Three options evaluated (no status / status+progress / status-only)
   - Option B selected: structured task_status() with progress_preview
   - Rationale: steer_task requires status; data already exists in output_file

4. Section 7.4: Status Query & Progress Design
   - task_status() return structure with 10 typed fields
   - progress_preview implementation (tail of output_file, 500-char cap)
   - list_tasks() companion tool for session task enumeration

5. Section 7.5: Multi-Layer Norm Constraint Design
   - Four layers: tool description, parameter design, runtime soft-limit,
     system prompt directive
   - Defense-in-depth against polling anti-patterns
   - Constraint effectiveness analysis table

6. Section 8.2: Expanded tool API signatures
   - task_status() with detailed docstring and use case scoping
   - steer_task() and list_tasks() added to provider API

7. Open questions 6-9: progress_preview limits, soft-limit configurability,
   list_tasks placement, binary output handling

8. Decision D5 recorded; status advanced from DRAFT to REVIEW

References: opencode at /Users/mollion-mo/Downloads/projects/opencode
@Million-mo
Million-mo changed the base branch from develop/agentic to main July 21, 2026 03:36

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a security-focused script to scan VCR cassettes for leaked credentials and updates configuration files to improve repository hygiene. The review identified a critical flaw in the credential scanning script: the current regex-based YAML parsing is brittle and prone to false negatives. I have included a suggestion to switch to a robust YAML parser (PyYAML) to ensure all sensitive headers are correctly identified regardless of formatting. No other issues were found in the provided changes.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

I am having trouble creating individual review comments. Click here to see my feedback.

.github/scripts/check_cassette_credentials.py (72-97)

critical

This regex-based approach to parsing YAML is not robust and will miss credentials in common VCRpy cassette formats, creating a false sense of security.

VCRpy often records headers with multiple values as a list under the header key, like this:

headers:
  Authorization:
  - Bearer my-secret-token

Your current regex will only match Authorization: with an empty value and will completely miss the line containing the actual token.

For a security-critical script like this, it's much safer to use a proper YAML parser like PyYAML. This ensures you correctly navigate the document structure to find all sensitive headers, regardless of formatting.

Here's a suggested implementation for scan_file using PyYAML. Note that while this approach loses precise line numbers, it guarantees correctness in finding leaked credentials, which is the primary goal. The Finding can use -1 for the line number to indicate a file-level finding, and the reporting logic can be adjusted accordingly. You will also need to add pyyaml to your dependencies.

import yaml
from yaml.error import YAMLError

def scan_file(path: Path) -> list[Finding]:
    """Scan a single cassette file for un-redacted credentials."""
    findings: list[Finding] = []
    try:
        data = yaml.safe_load(path.read_text(encoding="utf-8"))
    except (OSError, YAMLError) as exc:
        print(f"WARNING: could not read or parse {path}: {exc}", file=sys.stderr)
        return []

    if not isinstance(data, dict) or "interactions" not in data:
        return []

    for interaction in data.get("interactions", []):
        if not isinstance(interaction, dict):
            continue
        for req_res_key in ("request", "response"):
            if not isinstance(interaction.get(req_res_key), dict):
                continue
            headers = interaction[req_res_key].get("headers", {})
            if not isinstance(headers, dict):
                continue

            for name, values in headers.items():
                if str(name).lower() in SENSITIVE_HEADERS:
                    values = values if isinstance(values, list) else [values]
                    for value in values:
                        if value is not None and not is_redacted(str(value)):
                            # Using -1 for line_number as it's not available with this method.
                            findings.append(Finding(path, -1, str(name), str(value)))
    return findings

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