Skip to content

design: 研究跨能力的可恢复资源引用,但不引入 OpenPI 全局资源路由器 #157

Description

@tt-a1i

一句话结论

OMP 把 agent output、artifact、history、issue/PR、skill 等投影为 URI,并让通用 read / grep 复用;OpenPI 已能落盘多类 Subagent、Workflow、Background Terminal 产物,但各 owner 的上游截断、完整性、引用格式和恢复生命周期不同。

值得研究的是一个 薄的、Pi-native resource reference contract:统一“怎么引用、怎么证明 owner、怎么按需读取”,同时保留各 extension 对生命周期和存储的所有权。不要复制 OMP 的 process-global router。

固定证据

对比固定在:

  • OpenPI main@2a69d3f32994da4123f1312b7fa84ef3d6119be1
  • OMP main@7623b960540518bb1291808bbae28332065e9dba

OMP 当前:

  • process-global router 注册 agent://artifact://history://issue://pr://skill://xd:// 等 handler:router
  • 通用 read schema 接受 local path、internal URI 或 URL:read surface
  • grep 也理解 internal URL 与 line selector;长工具输出可留下 artifact://<id> 恢复引用:grep resource handling, recoverable output

OpenPI 当前已经有的优势:

  • Direct Subagent 的长 manager snapshot 可保存为 content-addressed、immutable、私有权限文件,并给 Pi native read 一个真实 path;但 manager 已先把 backend final 限制为 1,024 × 1,024 个 JS code units,因此该 artifact 不能证明更早的 backend output 完整性:manager cap, subagent artifact, bounded projection
  • Workflow 对 transcript、agent result、journal、result/workflow manifest 分别持久化并有独立预算:workflow artifacts, agent result
  • 各能力工具面保持 owner 分组与渐进披露:tool ownership

为什么值得讨论

现在模型拿到的恢复入口可能是:

  • 一个绝对文件 path;
  • 一个 run-relative artifact;
  • 一个 tool-specific id;
  • 一个需要调用 subagent_check / workflow_status / bg_watch 才能继续读取的对象。

这些都能工作,但跨能力综合时,父模型需要记住多套寻址方式。一个小而稳定的 reference shape 可以让 projection 更短、handoff 更可移植,也能减少为了“读完整产物”新增 workflow-specific model tools 的压力。

关键边界:不要照搬 OMP 的全局路由

OMP 的全局 router 对独立产品合理,但 OpenPI 的 contract 要求 Pi 继续拥有 Session、普通 tools 和 source of truth。建议只研究:

type OpenPiResourceRef = {
  owner: "subagent" | "workflow" | "background";
  id: string;
  revision?: string;
  mediaType?: string;
  byteLength?: number;
}

这只是示意,不是预先批准的 API。resolve 必须回到 owner extension 或 Pi 已有 resource seam;不能建立第二个全局存储表。

需要回答的问题

  • Pi 是否已有 extension resource / attachment / artifact seam 可复用?
  • reference 如何绑定 Session/branch/run owner,避免 stale id 指向错误对象?
  • path 型 artifact 如何防目录穿越、symlink、跨 trust root 与清理后悬空?
  • immutable artifact、live stream、owner-lost workflow 的读取语义是否必须不同?
  • 是否只需要统一 metadata/ref,不需要统一 read/grep?
  • handoff/resume 后引用如何证明仍可读?不可读时如何明确失败?
  • 是否能保持 ordinary parent turn zero-resident,仅在结果投影中出现 compact ref?

非目标

  • 不为 issue/PR、skill、memory 重建一套 OpenPI URL scheme;
  • 不接管 Pi native read
  • 不建立 process-global mutable router;
  • 不把所有产物搬进同一目录或数据库;
  • 不让 reference 绕过 child/tool 权限;
  • 不用漂亮 URI 掩盖 artifact 已丢失或 owner uncertain。

完成条件

  • 盘点 Pi 现有 resource/artifact seam,并先证明是否真的缺 seam
  • 定义 owner、identity、revision、liveness、authorization 与 cleanup 语义
  • 至少覆盖 Direct Subagent、Workflow、Background Terminal 三种不同 lifecycle
  • stale、missing、owner-lost、unauthorized 必须是可区分失败
  • reference 不增加普通回合常驻工具,读取仍服从 Pi trust/tool boundary
  • 用一次跨能力 handoff 比较现状 path/id 文案与 compact ref 的 token/恢复成功率
  • 若统一 abstraction 比三种 owner adapter 更复杂,记录不采用结论

与现有 Issue 的关系


2026-09 fixed-source addendum: canonical bytes, bounded projections, recovery, and RAG boundary

Research status

Five independent source workstreams completed without failure, followed by synthesis and a separate adversarial verification pass.

Fixed baselines:

  • OpenPI 2a69d3f32994da4123f1312b7fa84ef3d6119be1
  • Pi @earendil-works/pi-coding-agent@0.84.3
  • Codex a9e447a69dee4f2789dd8d8c776e314772c1f049
  • Hermes cbd8de8ad64530be01efea23b7764d5c37c634ed
  • Grok Build c2ad97f87aea4303b6000a2c22128bc91ee76c9b
  • Gemini CLI 812f7a2bcf20b6e80e2e50c3c8fa8e26567bc1e8
  • OpenCode 8615731d46153dd29b89e205fb55b2cc16205cb0
  • Claude Code: official rolling documentation only; proprietary persistence internals remain unknown.

Material correction to the original Issue

The original wording overstates current preservation as “reliably persisted complete outputs.” At the fixed OpenPI revision, several “full” artifacts are exact only relative to an already bounded runtime value, not the backend/provider’s original output.

Direct Subagent

SubagentManager first slices a completed backend answer to 1,024 × 1,024 JavaScript code units:

s.finalText = outcome.finalText.slice(0, FINAL_TEXT_MAX_LENGTH);

Only that bounded snapshot.finalText later reaches projectResult(). The SHA-256 artifact is immutable and byte-exact for the manager snapshot, but cannot prove preservation of backend output beyond the manager cap.

Evidence:

Therefore Issue #64’s “完整 final artifact” contract is satisfied only up to the manager cap. This Issue must not repeat it as complete backend output.

Workflow Agent

A Workflow child’s final assistant output is truncated to 64 KiB before it is returned to the coordinator:

output = truncateUtf8(finalOutput(childSession.messages), AGENT_OUTPUT_MAX_BYTES);

persistWorkflowAgentResult() then uses encodeCompleteJson() and fails closed if the already-bounded result cannot fit its 2 MiB/depth/node/string budgets. Thus agent-results/agent-NNNN.json is complete-or-fail for the coordinator value, not for arbitrary child/provider output.

Evidence:

The separate result.json has weaker semantics. It uses safeStringify() and may contain normalized/truncated fields or an entire preview object when over budget. It is not a universal canonical result artifact.

Evidence:

Workflow result references

Workflow resultRef values live in an in-memory Map and are valid only in the same run. Persisting the opaque string does not make it resolvable after restart. A run-relative artifact path is provenance, not an automatically authorized child-readable handle.

Evidence: handoff registry.

Directory/privacy qualification

Direct-child CAS directories explicitly reject symlink components and use private modes. Workflow artifact files are written with 0600, but their recursively created directories do not establish a uniform explicit 0700 contract in this path. Documentation must describe owner-specific controls, not claim universal private artifact directories.

Evidence:

Required taxonomy

Use these terms consistently:

  1. Source execution bytes — bytes emitted by a provider, child process, tool or backend before OpenPI bounds them.
  2. Owner-normalized result — the value an owning extension accepts after parsing, caps and normalization.
  3. Canonical owner artifact — authoritative persisted bytes for that explicitly declared owner value.
  4. Transcript copy — Session/history representation; potentially compacted, masked or reconstructed.
  5. Bounded projection — a head/tail/preview derived for model or UI budgets.
  6. Resource reference — owner-bound identity and recovery metadata; neither storage nor authority.
  7. Live handle — process/session/run identity for observation/cancellation; not durable content identity.
  8. Search/index projection — rebuildable lookup state; never canonical evidence.
  9. Semantic retrieval/RAG — a derived candidate-selection system, not persistence or proof.
  10. Provider file object — provider-scoped upload/download identity; not local canonical evidence.
  11. Delivery receipt — evidence of transport attempt/outcome, independent from execution and completeness.
  12. UI rendering — presentation only.

The desired dependency direction is:

execution owner
  → declared owner-normalized value
  → optional canonical owner artifact
  → bounded projection + owner-bound reference
  → Pi-native read/search
  → model/UI

The declaration of what is canonical must name its boundary. “Complete” without “complete relative to X” is invalid.

Current OpenPI matrix

Owner Persisted material Known bound before persistence Projection/recovery semantics
Direct Subagent SHA-256 text artifact for long manager snapshots; wx, 0600, collision verification manager slices backend final text to 1,048,576 JS code units head/tail projection; Pi read path; artifact-write failure is explicit
Workflow Agent agent-results/agent-NNNN.json, fail-closed encoding runner truncates final assistant output to 64 KiB same-run handoff is bounded; run-relative path is provenance
Workflow transcript transcripts.json per-entry and total artifact budgets; old middle omitted explicitly bounded history copy, not canonical output
Workflow final result result.json safeStringify, 1 MiB outer budget, normalization/preview fallback useful terminal artifact; completeness not guaranteed
Workflow journal bounded journal.json old entries may be dropped at journal cap replay projection; malformed/missing journal becomes a miss
Background terminal per-stream temporary spill spill cap, flush timeout and owner cleanup bounded retained tail plus temporary path while owner retains it
rg / fd capture temporary complete output only below capture cap over-cap partial capture is deleted Pi-standard bounded preview plus path when recoverable
Pi Session JSONL branch transcript compaction alters future model projection, not stored earlier entries Session evidence, not a generic execution-artifact store

This matrix exposes two different problems:

A reference cannot recover bytes that its owner discarded before publication.

Lifecycle and receipts

Artifact state must be orthogonal to execution and delivery:

Execution: accepted → running → completed | failed | aborted | uncertain
Resource:  absent → writing → complete | partial | unavailable
           complete|partial → stale | expired | deleted
Delivery:  none → held-for-inline | pending → delivered | failed

A machine-readable receipt should keep at least:

executionStatus
ownerValueCompleteness
sourceCoverage
resourceStatus
deliveryStatus

Definitions:

  • complete: canonical bytes are committed and match the declared owner value; this says nothing about bytes lost before that value was formed.
  • partial: a known prefix/tail/range exists and omissions are known.
  • uncertain: execution, side effects, terminal outcome or persistence cannot be proven.
  • unavailable: no recoverable artifact was published.
  • delivered: a transport completed; it does not imply any completeness state.

Publication rule: never emit a recovery reference before its target is readable. Spill failure, cap exhaustion, flush timeout, owner loss or missing data must never become empty success.

Identity, revision, liveness and authorization

If trace evidence eventually justifies #157’s thin contract, the smallest useful reference shape is approximately:

ownerKind
ownerId
ownerGeneration
relativeArtifactId
revisionOrDigest?
byteLength?
lineCount?
sourceCoverage
resourceCompleteness
createdAt
expiresAt?

This is not a pre-approved API. Resolution remains delegated to the owner extension.

Required behavior:

  • constrain identifiers and resolve relative to the owner root;
  • validate containment and real paths;
  • reject traversal and symlink substitution;
  • bind Session/run/generation so stale references cannot resolve to replacement owners;
  • apply Pi Trust and parent/child tool authority independently of possession of the reference;
  • distinguish forbidden, missing, stale, expired, partial, unavailable and uncertain;
  • do not use absolute model-supplied paths as authority;
  • do not introduce bearer-like global references or a process-global registry.

Content digest proves byte identity, not who produced the bytes or whether they cover the original execution stream. Replay fingerprint proves eligibility for reuse, not artifact identity. Live process ID proves liveness, not durable content.

Child, fork, resume, compaction and replay

  • Direct child continuation uses the native child Pi Session, not its result artifact.
  • Workflow operator reuse is same-run and in-memory; persisted resultRef tokens do not restore the registry.
  • A fork or child gets only the history/resources/tools explicitly reconstructed for it; a reference cannot widen child authority.
  • Workflow replay identity remains separate from artifact identity.
  • A verified replay hit reuses a persisted result; a missing/malformed journal is a miss, not proof of prior failure.
  • Compaction summaries and bounded transcripts are derived context. They cannot establish that all execution evidence remains recoverable.
  • Workflow artifact files are individually atomic; workflows: terminal artifact set (result.json + workflow.json) is not committed atomically #110 separately owns the crash window across the terminal artifact set.
  • Cleanup provenance and owner-loss preservation remain workflows: forced settlement can skip persisting worktree cleanup metadata (provenance loss) #114’s scope.

Cross-system findings

Codex

At a9e447a, rollout/thread storage is the primary durable execution-history source used for resume/fork reconstruction. Exec results retain truncation metadata such as original token count and omitted bytes, but the inspected path does not provide a universal stable spill artifact or range/search API for every omitted output.

Knowing that bytes were omitted is stronger than silent truncation, but it is not recovery.

Codex can also transform declared MCP file parameters into provider file IDs/download URLs. Those provider objects have a different authority, retention and identity plane from local execution artifacts.

Sources:

Claude Code

Official rolling documentation establishes persisted/resumable Sessions, transcript export, tools, MCP resources, background work and subagents. It does not expose enough implementation detail to prove:

  • a universal canonical artifact store;
  • exact preservation after tool-output truncation;
  • provider-file ownership and retention;
  • a single range/search resource-reference contract;
  • internal semantic retrieval over execution evidence.

UI labels such as file, result, transcript or download are not sufficient evidence.

Sources:

Hermes

Hermes documents large-result spill paths and offset-based read_file recovery, and its SQLite/FTS search returns derived snippets/metadata. In the pinned checkout, imported spill modules were absent from the inspected source tree, so spill atomicity, TTL and all-path authorization must remain unknown rather than inferred from documentation.

Session FTS is an index projection. It does not make snippets canonical evidence.

Source: Hermes fixed tree.

Grok Build

Grok distinguishes authoritative updates.jsonl from a rebuildable chat-history cache. Background task/subagent records expose live task identity, output path, total bytes and truncation state; output can be fetched on demand, and ordinary files support ranged reads.

Its FTS and optional vector mechanisms are search/memory projections, not universal execution-artifact authority. A generic content-addressed result plane and delivery receipt were not established by the inspected fixed source.

Source: Grok Build fixed tree.

Gemini CLI

Gemini can mask older tool output from model history while writing the prior content under project-temporary tool-output files and replacing it with size/line/path metadata. This is spill-plus-projection, not immutable content addressing.

Checkpoint files in the inspected path are direct writes rather than a proven transactional artifact set; invalid/missing checkpoint loading can fall back to empty history. Provider content parts remain distinct from local canonical evidence.

Sources:

OpenCode

OpenCode persists tool calls/results as Session parts and carries truncation/output-path metadata for managed outputs. Attachments may become provider-shaped media/data parts. Compaction can clear old model-visible tool content while retaining Session metadata.

The supplied pinned checkout did not expose enough of the managed truncation implementation to establish exact storage limits, atomicity, cleanup or symlink behavior. No semantic execution-evidence index or universal artifact receipt was proven.

Sources:

RAG and index boundary

Execution owners may expose stable text references. They must not silently become a semantic-memory subsystem.

  • Pi read plus ordinary text search remains the default recovery path.
  • Search indexes are rebuildable projections, never evidence authority.
  • This Issue does not create chunking, embeddings, reranking, citations, a vector DB or cross-run corpus.
  • Any future semantic indexing requires memory: 研究 Project-scoped Durable Learning,并严格区分事实、经验与 Skill #167’s durable-learning decisions for source authorization, provenance, invalidation, retention and user control.
  • Bounded transcripts must not be vectorized and described as complete execution-evidence retrieval.
  • Index commit and canonical artifact commit require separate receipts; an index failure cannot retroactively make a durable artifact write fail, and an artifact write cannot be reported searchable before index confirmation.

Retention, deletion and privacy

Retention remains owner-specific. A thin reference may report owner policy and current liveness but must not add global garbage collection.

Documentation must distinguish:

  • immutable content identity from indefinite retention;
  • temporary spill lifetime from Session lifetime;
  • owner-lost artifacts from live handles;
  • deletion success from reference invalidation;
  • filesystem mode from per-artifact authorization;
  • local artifact bytes from provider-hosted file retention;
  • redaction/secret scanning from truncation.

Unknowns at the fixed revision include a uniform TTL, sensitivity classification, redaction ledger, universal artifact ACL, deletion reason/timestamp, crash durability via file/directory fsync, and cross-owner retention manifest.

Correct relationship to existing Issues

Decision

Do not implement a new artifact runtime now.

  1. First correct documentation and tests so “complete” always names the owner boundary.
  2. Collect concrete traces where existing paths plus Pi read/text search fail materially.
  3. If such traces justify design: 研究跨能力的可恢复资源引用,但不引入 OpenPI 全局资源路由器 #157, define one compact internal reference shape shared by existing owner adapters.
  4. Keep resolution, retention and authorization with each owner.
  5. Keep the reference absent from child tool surfaces unless independently classified child-safe.
  6. Add no global store, URI router, database, index, RAG service or model-facing read/search tool.

Revised acceptance criteria

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions