Skip to content

feat(orchestration): connect a co-located local CLI agent + fix inbound peer attribution#4777

Open
oxoxDev wants to merge 2 commits into
tinyhumansai:mainfrom
oxoxDev:feat/orchestration-cli-connect
Open

feat(orchestration): connect a co-located local CLI agent + fix inbound peer attribution#4777
oxoxDev wants to merge 2 commits into
tinyhumansai:mainfrom
oxoxDev:feat/orchestration-cli-connect

Conversation

@oxoxDev

@oxoxDev oxoxDev commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Two fixes for the coding-agent → OpenHuman orchestration bridge: (1) a freshly-launched local CLI agent now connects with no manual contact-approval click, and (2) an inbound peer Master DM now renders on the correct (left) side instead of the owner's side.

Problem

Handshake: a fresh CLI identity sends a tiny.place contact request, but auto-accept only ever accepted already-linked ids — so the request sat pending and the CLI's session stream was dropped by the sender gate until a human clicked accept. A contact request carries no owner declaration on the wire, so OpenHuman could not recognise a co-located CLI from the request alone.

Attribution: a plain (non-harness) DM is only ever classified on the inbound decrypt path, so its author is always the peer — never us. It was stamped role "user", which the transcript treats as owner-authored and right-aligns, so an incoming peer DM stacked on the owner's own side (both halves of a two-way conversation rendered right).

Solution

Handshake (agent_orchestration/pairing.rs): a same-machine handshake — the CLI writes { agentId, owner, ts } to ~/.openhuman/local-agents.json before it requests contact. auto_accept_linked_contact_requests now also accepts a pending requester whose id appears in that file under a fresh entry that names this OpenHuman as owner. Same-user filesystem access is the trust proof; the owner-match stops a CLI aimed at a different local OpenHuman from being cross-accepted, and a 1h TTL stops a departed agent's id lingering as auto-acceptable. Both trust sources stay fail-closed (missing/corrupt file, locked wallet, stale/undated entry → trust nothing). Id + owner matching reuses resolve_linked_id, so base64/base58 encodings unify.

Attribution (orchestration/ingest.rs): stamp an inbound Master DM role "peer" (not "user") so the transcript left-aligns it; our own outgoing Master message is persisted separately as "owner" and stays right.

The CLI side that writes the handshake file is a companion PR in tinyhumansai/tiny.place (#242).

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case)
  • Diff coverage ≥ 80% — not run locally; new lines are covered by the added unit tests (5 pairing + 1 ingest), CI gate will confirm
  • Coverage matrix updated — N/A: behaviour-only change, no new feature row
  • All affected feature IDs listed under ## Related — N/A: no matrix feature touched
  • No new external network dependencies introduced (local file read only; no new endpoints)
  • Manual smoke checklist updated if this touches release-cut surfaces — N/A: orchestration pairing internals
  • Linked issue closed via Closes #NNN — N/A: bridge-epic work, no tracking issue

Impact

  • A local tinyplace codex/claude connects to its OpenHuman on the same machine with zero manual pairing.
  • Two-way peer Master DMs render with correct left/right attribution.
  • No behaviour change for remote/unknown senders — they are still left pending for the human (generic auto-accept stays off).

Related

Companion CLI change: tinyhumansai/tiny.place#242 (writes ~/.openhuman/local-agents.json).

AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

N/A — not a Linear/Codex PR.

Commit & Branch

Authored with Claude Code assistance. Branch feat/orchestration-cli-connect; commits 73c9d25 (attribution) + 589ce6d (handshake).

Summary by CodeRabbit

  • New Features

    • Contact requests from trusted local pairing agents can now be accepted automatically.
    • Trust is limited to valid, recent local pairing information.
  • Bug Fixes

    • Inbound Master messages are now correctly identified as peer messages.
    • Peer messages display with the appropriate transcript alignment instead of appearing as user-authored messages.

oxoxDev added 2 commits July 10, 2026 14:10
A plain (non-harness) DM is only ever classified on the inbound decrypt
path, so its author is always the peer, never us. It was stamped role
"user", which the transcript treats as owner-authored and right-aligns
— so an incoming peer DM stacked on the owner's own side (both halves of
a two-way conversation rendered right). Stamp "peer" instead; our own
outgoing Master message is persisted separately as "owner" and stays
right.
A freshly-launched local coding-agent CLI cannot link to its OpenHuman
without a manual contact-request approval: the CLI sends a contact
request, but auto-accept only ever accepted already-linked ids, so the
request sat pending and the CLI's session stream was dropped by the
sender gate until a human clicked accept. A tiny.place contact request
carries no owner declaration on the wire, so OpenHuman cannot recognise a
co-located CLI from the request alone.

Add a same-machine handshake: the CLI writes { agentId, owner, ts } into
~/.openhuman/local-agents.json before it requests contact. Auto-accept
now also accepts a pending requester whose id appears in that file under
a FRESH entry that names THIS OpenHuman as owner. Same-user filesystem
access is the trust proof; the owner-match stops a CLI aimed at a
different local OpenHuman from being cross-accepted, and the 1h TTL stops
a departed agent's id lingering as auto-acceptable. Both sources stay
fail-closed (missing/corrupt file, locked wallet, stale/undated entry all
trust nothing). Encoding-agnostic id + owner matching reuses
resolve_linked_id.
@oxoxDev oxoxDev requested a review from a team July 10, 2026 12:32
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds fail-closed local handshake trust with timestamp validation to contact auto-acceptance, and classifies decrypted plain Master inbound DMs as peer-authored.

Changes

Local pairing trust

Layer / File(s) Summary
Handshake trust gating
src/openhuman/agent_orchestration/pairing.rs
Adds local handshake parsing, owner identity matching, and RFC3339 freshness checks with TTL and future-skew bounds.
Contact auto-acceptance integration
src/openhuman/agent_orchestration/pairing.rs
Combines linked and local-trusted agent ids, preserves fail-closed behavior, updates debug counts, and tests trust boundaries.

DM role classification

Layer / File(s) Summary
Master DM peer role
src/openhuman/orchestration/ingest.rs
Changes plain Master DM fallback messages from user to peer and updates assertions accordingly.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ContactRequester
  participant AutoAccept as auto_accept_linked_contact_requests
  participant LocalAgents as local-agents.json
  participant Identity as resolve_linked_id
  ContactRequester->>AutoAccept: submit contact request
  AutoAccept->>LocalAgents: load local handshake entries
  AutoAccept->>Identity: resolve local OpenHuman signer
  Identity-->>AutoAccept: local identity
  AutoAccept->>AutoAccept: validate owner and timestamp
  AutoAccept-->>ContactRequester: accept only trusted requester
Loading

Possibly related PRs

Suggested labels: feature, rust-core, agent

Poem

A bunny checks the handshake bright,
Rejects stale hops outside the light.
Trusted friends may pass the gate,
While peer DMs find their proper state.
Tiny paws approve the flow! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the two main changes: local CLI agent pairing and inbound peer attribution.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

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

@coderabbitai coderabbitai Bot added agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels Jul 10, 2026

@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: 589ce6da9c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +387 to +388
match std::fs::read(&path) {
Ok(bytes) => serde_json::from_slice(&bytes).unwrap_or_else(|e| {

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 Validate permissions before trusting local handshakes

Because this file becomes the trust proof for auto-accepting a contact request, reading and trusting any ~/.openhuman/local-agents.json that is merely readable is unsafe on multi-user systems where the directory or file is group/world-writable (for example from a permissive umask or shared home). In that case another local account can write a fresh entry naming this owner and have its agent contact auto-accepted; the reader should fail closed unless the file and parent directory are owned by the current user and not writable by others (or otherwise use a private, mode-checked location).

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/openhuman/orchestration/ingest.rs`:
- Around line 181-192: The ClassifiedMessage role change to "peer" must be
coordinated with every downstream consumer. Trace consumers of ClassifiedMessage
and persisted roles, updating Claude Code ingestion, history prompt
construction, system flattening, and memory extraction to treat "peer" as
inbound user content while preserving correct display alignment; alternatively
retain "user" for inference and add a separate author/display field. Add
end-to-end coverage proving inbound peer messages are included in prompts,
histories, flattened systems, and memory extraction.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ab86560d-10fd-4b1b-85f7-3564d4007ec2

📥 Commits

Reviewing files that changed from the base of the PR and between f5b77ed and 589ce6d.

📒 Files selected for processing (2)
  • src/openhuman/agent_orchestration/pairing.rs
  • src/openhuman/orchestration/ingest.rs

Comment on lines +181 to +192
//
// This path only ever runs on an INBOUND, decrypted DM (the counterpart is
// the sender — see `ingest_one`), so the author is the PEER, never us. Stamp
// `"peer"` rather than `"user"`: the transcript treats `you`/`owner`/`user`
// as owner-authored and right-aligns them, so a peer's incoming Master DM was
// rendering on the owner's side (both halves of a two-way DM stacked right).
// `"peer"` is not owner-authored → it left-aligns as the counterpart. Our own
// outgoing Master message is persisted separately as `"owner"` and stays right.
ClassifiedMessage {
chat_kind: ChatKind::Master,
session_id: "master".to_string(),
role: "user".to_string(),
role: "peer".to_string(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Update downstream consumers before changing this role.

Persisting "peer" fixes alignment, but current consumers only recognize "user" for inbound content: Claude Code drops "peer" rows, history providers may send an empty prompt, system flattening may insert a synthetic user, and memory extraction skips user-only preferences/commitments. Either preserve "user" for inference semantics with a separate display/author field, or update all consumers and add end-to-end coverage before merging.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/openhuman/orchestration/ingest.rs` around lines 181 - 192, The
ClassifiedMessage role change to "peer" must be coordinated with every
downstream consumer. Trace consumers of ClassifiedMessage and persisted roles,
updating Claude Code ingestion, history prompt construction, system flattening,
and memory extraction to treat "peer" as inbound user content while preserving
correct display alignment; alternatively retain "user" for inference and add a
separate author/display field. Add end-to-end coverage proving inbound peer
messages are included in prompts, histories, flattened systems, and memory
extraction.

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

Labels

agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant