迁移路径: /run/media/airlongdian/EasyU/AirCoding -> /home/airlongdian/DataDevices/AirWorkSpace/AirCoding Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
17 KiB
Executable File
17 KiB
Executable File
Architecture Decisions — Round 3
Date: 2026-05-26 Source: implementation-interface freeze discussion
D-038: RuntimeEvent Envelope Uses Route Chain
- Decision: Runtime events use a structured
route: string[]route chain instead of correlation/causation IDs. - Reason: Route chain is easier to display, append, and inspect across Main Agent → Architecture Designer → Scheduler → Worker → Tool flows.
- Envelope:
interface RuntimeEvent<T = unknown> {
id: string
type: string
version: number
timestamp: string
session_id: string
project_id?: string
source: EventSource
route: string[]
payload: T
}
- Durability: Not declared by the event. EventStore decides durability by event type.
D-039: IPC Uses NDJSON over stdio
- Decision: Parent Scheduler and child agents communicate via NDJSON over stdio.
- stdout: Protocol only (
event,control,logmessages). - stderr: Crash fallback and non-structured fatal diagnostics only.
- Message union:
type IpcMessage =
| { kind: "event"; event: RuntimeEvent }
| { kind: "control"; control: ControlMessage }
| { kind: "log"; level: "debug" | "info" | "warn" | "error"; message: string; data?: unknown }
- Exit codes:
0: protocol-level completion, including task completed/blocked/failed1: uncaught exception2: startup/protocol error3: permission error4: parent cancelled5: hard timeout killed
D-040: Durable Event Type Set
- Durable:
session.created,session.archived,session.deleteduser.message.created,assistant.message.createdagent.started,agent.completed,agent.failedtask.created,task.started,task.completed,task.blocked,task.failed,task.cancelledtool.started,tool.completed,tool.failedcommand.started,command.completed,command.failedartifact.createdcontext.compaction.completed,summary.createdmemory.candidate.created,memory.promoted,memory.archiveddebug.record.createdpermission.decision.recordedrequirement.changed,architecture.plan.updated,architecture.impact.completed
- Ephemeral only:
agent.heartbeat,task.progress,token.delta,stdout.delta,stderr.delta,hud.frame.rendered,tool.progress
- Rationale: Persist tool/agent starts so crash recovery can detect half-finished operations; avoid persisting high-frequency stream deltas.
D-041: TaskSpec Contract
interface TaskSpec {
id: string
type: "execute" | "review" | "debug" | "compact" | "mine_experience"
title: string
description: string
acceptance_criteria: string[]
scope: {
write_area?: string
expected_files?: string[]
allowed_paths?: string[]
denied_paths?: string[]
}
dependencies: { hard: string[]; soft: string[] }
verification: {
commands?: string[]
required: boolean
fallback_allowed: boolean
}
constraints: {
max_turns: number
soft_timeout_ms: number
hard_timeout_ms: number
retry_budget: number
model_policy: "scheduler_forced" | "agent_select"
model_id?: string
}
context_refs: {
plan_ref?: string
arc_ref?: string
parent_task_results?: string[]
artifacts?: string[]
}
output_contract: "ExecutorResult" | "ReviewerResult" | "DebuggerResult" | "CompactorResult" | "ExperienceMinerResult"
}
- allowed_paths/denied_paths are task-level narrowing rules on top of global PermissionEngine.
- verification.commands are Scheduler recommendations; agents may add more and must report actual commands run.
- retry_budget is per task.
D-042: WorkerResult Contract
interface WorkerResult<T = unknown> {
task_id: string
agent_id: string
agent_type: "executor" | "reviewer" | "debugger" | "compactor" | "experience_miner"
status: "completed" | "failed" | "blocked" | "cancelled"
summary: string
changed_files: string[]
diff_ref?: string
artifacts: ArtifactRef[]
verification: VerificationResult[]
risks: Risk[]
follow_up_tasks: FollowUpTask[]
evidence_refs: EvidenceRef[]
result: T
}
- failed: task goal not achieved; Scheduler may retry or skip.
- blocked: upper-level decision needed; continued attempts are not useful.
- summary: human-readable 3–6 sentence summary covering what was done, evidence, conclusion, and risk. It is for TUI/Main Agent display, not scheduling logic.
- changed_files exists for all worker types and may be empty.
D-043: ArtifactRef and EvidenceRef Separation
- Artifact: persistent file or large data object (build log, test log, screenshot, pcap, core dump, diff, terminal cast).
- Evidence: a claim-supporting reference that may point to an artifact excerpt, structured result, message, tool run, command run, or diagnostic.
interface ArtifactRef {
id: string
type: "build_log" | "test_log" | "screenshot" | "pcap" | "core_dump" | "terminal_cast" | "diff" | "report" | "other"
uri: string
size_bytes?: number
sha256?: string
created_at: string
}
interface EvidenceRef {
id: string
kind: "artifact_excerpt" | "structured_result" | "message" | "tool_run" | "command_run" | "diagnostic"
ref: string
location?: { line_start?: number; line_end?: number; byte_start?: number; byte_end?: number }
claim: string
}
D-044: Tool API Contract
interface ToolDefinition<I = unknown, O = unknown> {
name: string
version: number
description: string
input_schema: JsonSchema<I>
output_schema: JsonSchema<O>
category: "filesystem" | "shell" | "build" | "test" | "debug" | "static_analysis" | "gui" | "network" | "memory" | "project" | "internal"
permissions: {
read_paths?: PathPolicy
write_paths?: PathPolicy
execute?: boolean
network?: boolean
system_sensitive?: boolean
}
streaming: boolean
execute(input: I, context: ToolExecutionContext): AsyncIterable<ToolEvent> | Promise<ToolResult<O>>
}
- Inputs and outputs are both JSON-schema validated.
- Streaming tools must emit a final
tool.resultcontainingToolResult. - Bash is a regular shell tool; PermissionEngine performs extra command risk analysis.
D-045: Capability Dependencies Are Managed by Doctor/Setup
- Capability manifests declare dependencies but do not install them directly.
air doctor/air setupdetect and repair missing dependencies.- First startup runs read-only doctor automatically.
- If issues exist, user is prompted to run fix.
- High-permission mode can use
announce_then_runfor dependency installation after the first startup; user not interrupting means allow. - First startup, even in high-permission mode, shows the report and asks before
doctor --fix. credentialsandsystem_sensitiverisks always require explicit confirmation.
interface DependencySpec {
id: string
kind: "executable" | "system_package" | "npm_package" | "pip_package" | "lsp_server" | "formatter" | "mcp_server" | "env_var" | "permission" | "service" | "network_port"
required_for: string[]
severity: "required" | "optional" | "degraded"
detect: DependencyDetectSpec
install?: {
low_permission: "never" | "prompt" | "safe_cache"
high_permission: "never" | "announce_then_run" | "safe_cache" | "prompt"
commands?: InstallCommandTemplate[]
docs?: string
}
risk: "none" | "downloads_code" | "needs_root" | "network_capture" | "credentials" | "system_sensitive"
}
D-046: ContextAssembler Contract
- ContextAssembler outputs Anthropic canonical messages. Provider-specific conversion happens only at the LLM adapter boundary.
- ContextAssembler records omissions so agents know what was not included.
- If usage passes compaction threshold, it publishes
context.compaction.requestedbut does not compact itself.
interface ContextRequest {
session_id: string
project_id: string
requester: { kind: "main" | "architecture_designer" | "scheduler" | "agent"; agent_type?: string; task_id?: string }
purpose: "user_response" | "architecture_planning" | "task_execution" | "review" | "debug" | "compaction" | "experience_mining"
model: { provider_id: string; model_id: string; context_window_tokens: number; max_output_tokens: number }
budget_policy: { reserved_output_tokens: number; safety_margin_tokens: number; target_usage_ratio: number }
include: {
project_rules: boolean
project_profile: boolean
task_graph: boolean
recent_messages: number
related_artifacts?: string[]
related_tasks?: string[]
related_files?: string[]
}
rule_set_ref?: string
}
interface AssembledContext {
request_id: string
messages: AnthropicMessageParam[]
included_refs: { messages: string[]; summaries: string[]; artifacts: string[]; rules: string[]; tasks: string[] }
token_estimate: { total: number; by_section: Record<string, number>; model_id: string }
compaction: { needed: boolean; reason?: string; requested_event_id?: string }
omissions: { ref: string; reason: string }[]
}
D-047: Compaction Rules Use Markdown + Frontmatter
- Rule files are Markdown with YAML frontmatter.
- Paths:
- Built-in system default
- User template:
~/.air/compaction-rules.md - Project override:
.air/shared/compaction-rules.md
- Three-tier inheritance: system default → user template → project override.
- Message classification is done by ContextClassifier before compaction.
drop_if_neededis allowed because original messages are preserved.
D-048: TUI Reuses OpenCode UI Primitives, Not Business State
- Use
@opentui/solid,@opentui/core, and@opentui/keymap. - Copy/adapt OpenCode's generic theme, dialog, toast, keymap, layout, spinner, border, markdown/code/diff rendering patterns.
- Do not reuse OpenCode's SDK/sync/session business layer.
- AirCoding defines its own event store, session/message/task/agent/tool state model.
- OpenCode session UI is used as a rendering reference only.
D-049: Project State Lives in .air/local, Shared Knowledge in .air/shared
- Project source of truth moves into the project directory:
<project>/.air/
shared/ # git-shareable project knowledge
local/ # portable but gitignored runtime state
.air/sharedcontains project profile, permissions, compaction rules, project rules, and plan/docs..air/localcontains sessions, artifacts, runtime state, backups, debug/learned DBs, locks, temp, and workspaces.~/.aircontains only user config, cache, global skills, global logs, and a project index.project_idis a stable UUID generated at initialization, not an absolute-path hash.
D-050: Developer Logs Use Development-Team Public Key Encryption
air.developer.logis encrypted with the development team's public key.- No local user private key is required for decrypting developer logs.
air doctor --bundlemay include full diagnostics and is not automatically redacted.- Rationale: redaction may remove information needed to debug real failures.
- Diagnostic bundles are never auto-uploaded; user must explicitly export/send them.
D-051: Session DB Uses Canonical Messages + Domain State Tables
messagesstores complete Anthropic canonical content JSON.message_draftsstores streaming assistant intermediate state for crash recovery and is deleted after final message completion.message_partsis not a source-of-truth table in MVP.- Domain tables are the source of truth for scheduling/recovery/query:
tasks,task_dependencies,task_attemptsagents,tool_runs,command_runsartifacts,diagnostics,evidence_refs,workspaces,events
ui_statestores lightweight UI recovery state only.- ProjectionStore rebuilds TUI view models from DB + live EventBus.
D-052: Query-Friendly Columns and Tables Are Preferred over Parsing JSON
- Canonical JSON preserves fidelity; frequently queried relations are extracted to columns/tables.
tool_runsandcommand_runsincludeorigin_message_id.artifactsinclude common foreign keys (task_id,agent_id,tool_run_id,command_run_id) while retaining generic associated entity fields.eventsextract source/task/agent/tool/command IDs and store bothroute_jsonandroute_text.task_dependencies,task_attempts,diagnostics,evidence_refs, andworkspacesare first-class tables.
D-053: UI State Is Flushed Periodically and on Exit
- UI changes are held in memory during interaction.
ui_stateflushes periodically (e.g. every 10 seconds) and on normal exit.- Crash/power loss may lose a few seconds of UI-only state, but never scheduling/message state.
D-054: Artifact Layout Is Project-Local
- Artifacts live under:
<project>/.air/local/sessions/<session-id>/artifacts/
- URI format:
artifact://project/<project-id>/session/<session-id>/<artifact-id>
- Layout:
artifacts/
command-runs/<command-run-id>/
tool-runs/<tool-run-id>/
builds/
tests/
screenshots/
pcaps/
core-dumps/
diffs/
reports/
- Internal filenames may use artifact IDs or semantic names; DB preserves
original_name. - Logs may be gzip-compressed; screenshots, pcaps, and core dumps are not double-compressed by default.
- Session delete/purge deletes artifacts; archive keeps them.
D-055: Schema Migration Requires User Confirmation
- Opening a project auto-detects
.airschema versions. - Old schema triggers a migration plan display.
- User confirmation is required even in high-permission mode.
- Migration backs up
.airfirst. - Migration failure must rollback.
D-056: HUD/TUI Consumes ProjectionStore Only
- DB is persistent state source.
- EventBus is real-time state source.
- ProjectionStore is the only display projection consumed by TUI/HUD.
- HUD does not query SQLite directly.
- ProjectionStore hydrates from DB on startup and applies EventBus updates during runtime.
- If EventBus disconnects/restarts, ProjectionStore rehydrates from DB.
- HUD presets only control visible fields, not underlying state.
D-057: UI Design Asset Capability Is Optional but Supported
- AirCoding is not a general creative-media agent, but software development often requires UI assets, icons, visual mockups, and design specs.
- Runtime supports an optional
ui-design-assetscapability. - MVP includes text/SVG/design-spec oriented tools:
- ASCII/wireframe mockup generation
- design specification generation
- SVG icon generation
- screenshot design analysis
- external image-generation prompt generation
- Bitmap image generation/editing is provider-backed and post-MVP.
- Generated design assets are artifacts first:
ui_mockupiconillustrationsvg_assetdesign_specdesign_prompt
- Generated assets are shown to the user before being written into project files. UI/design choices are subjective and should not be silently finalized even in high-permission mode.
D-058: Anthropic Claude Skills Are a Tool/Skill Reference Source
- Anthropic/Claude open-source Skills are included as a reference for AirCoding's skill and tool organization.
- AirCoding should study and borrow:
SKILL.mdstructure and frontmatter conventions- skill directory layout (
scripts/,references/,assets/) - how reusable workflows are packaged as discoverable skills
- how skill descriptions guide trigger/retrieval behavior
- how skills interact with project rules and tool/capability execution
- Claude Skills are a reference for AirCoding's SkillGenerator, ExperienceMiner output format, and Capability documentation.
- AirCoding still keeps Project Rules, Skills, MCP, and Capabilities as separate concepts:
- Project Rules: authoritative project constraints
- Skills: reusable procedural knowledge
- MCP: external service/tool protocol
- Capabilities: runtime-registered tool bundles with dependencies/triggers/evidence types
D-059: Execution-Layer Primitives Align With Claude Code for Code Quality
- AirCoding should align execution-layer behavior with Claude Code as much as possible to maximize code quality, correctness, and safe modification behavior.
- Claude Code is the primary behavioral reference for execution-layer primitives.
- This includes:
- file read/edit/write safety boundaries
- exact and conservative diff/update application semantics
- patch granularity and conflict handling
- tool input/output schema style
- permission checks around filesystem and shell operations
- TAOR/TORI-style execution loops and result feedback patterns
- read-before-edit discipline
- small-step edits with verification before completion
- avoiding unrelated refactors and premature abstractions during task execution
- build/test/debug evidence collection before declaring completion
- project-rule and memory adherence during edits
- failure handling that diagnoses root cause instead of random retries
- explicit blocker escalation when implementation discovers architecture/interface conflicts
- OpenCode remains the runtime/TUI structure reference, but execution primitives must favor Claude Code semantics whenever there is a tradeoff.
- Codex remains a reference for broad tool surface and shell/patch/test direct loops, but AirCoding should not sacrifice Claude Code-style edit discipline for tool breadth.
- Rationale: Executor correctness, safe code modification, patch quality, verification discipline, project-rule adherence, and failure recovery matter more than matching OpenCode's internal execution implementation or Codex-style general tool breadth.