Skip to content

feat(hooks): cross-platform terminal identity [OMN-7295] - #1069

Merged
jonahgabriel merged 2 commits into
mainfrom
jonah/omn-7295-terminal-identity
Apr 2, 2026
Merged

jonahgabriel merged 2 commits into
mainfrom
jonah/omn-7295-terminal-identity

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Apr 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • PPID-based terminal ID generation that persists across /clear and session restarts
  • Each terminal tab gets a unique ID stored in .onex_state/terminal/tid_{ppid}
  • Heuristic bootstrap for Phase 2 agent binding (known limitations documented)
  • Cross-platform: macOS, Linux, Windows (best-effort)

Test plan

  • 4 unit tests: create, idempotency, isolation, format validation
  • Pre-commit hooks pass
  • ruff format/check clean

Part of Epic OMN-7291 (Agent Identity & Session Continuity Phase 2)

Summary by CodeRabbit

  • New Features

    • Terminal sessions now receive stable, per-tab identifiers that are generated, validated, and persisted to support consistent session-specific state.
  • Tests

    • Added unit tests covering ID generation, format validation, persistence across the same state storage, and uniqueness across different state locations.

…t binding [OMN-7295]

PPID-based terminal ID generation that persists across /clear and survives
session restarts. Each terminal tab gets a unique ID stored in
.onex_state/terminal/tid_{ppid}. Heuristic bootstrap for Phase 2.
@coderabbitai

coderabbitai Bot commented Apr 2, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6b0c71b6-e79f-49d2-b777-417efd99c93b

📥 Commits

Reviewing files that changed from the base of the PR and between 8500867 and 23f7743.

📒 Files selected for processing (1)
  • plugins/onex/hooks/lib/terminal_identity.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • plugins/onex/hooks/lib/terminal_identity.py

📝 Walkthrough

Walkthrough

A new module adds best-effort "stable per terminal tab" ID generation and on-disk persistence, plus validation. Unit tests exercise generation, persistence, uniqueness across state dirs, and format checks.

Changes

Cohort / File(s) Summary
Terminal Identity Library
plugins/onex/hooks/lib/terminal_identity.py
New module implementing shell-process key derivation (PPID-based with fallback), persistent terminal ID storage under a state root (default ~/.onex_state/terminal/), get_or_create_terminal_id() and is_terminal_id_valid() functions.
Unit Tests
tests/unit/hooks/lib/test_terminal_identity.py
New test suite with four cases: validates generated ID format, persistence across calls using same state dir, uniqueness across different state dirs, and overall validation function behavior.

Sequence Diagram(s)

sequenceDiagram
    participant Shell as ShellProcess
    participant Module as terminal_identity.py
    participant FS as FileSystem
    participant Host as HostnameService

    Shell->>Module: call get_or_create_terminal_id(state_dir)
    Module->>Module: compute shell key (PPID/PID fallback)
    Module->>FS: ensure state_dir/terminal exists
    alt id file exists
        Module->>FS: read tid_<shell_key>
        FS-->>Module: stored_id
        Module->>Module: validate stored_id (is_terminal_id_valid)
        alt valid
            Module-->>Shell: return stored_id
        else invalid
            Module->>Host: get hostname
            Host-->>Module: hostname
            Module->>Module: generate new ID ("terminal-"+hostname+uuid)
            Module->>FS: write tid_<shell_key> with new ID
            Module-->>Shell: return new ID
        end
    else id file missing
        Module->>Host: get hostname
        Host-->>Module: hostname
        Module->>Module: generate new ID ("terminal-"+hostname+uuid)
        Module->>FS: write tid_<shell_key> with new ID
        Module-->>Shell: return new ID
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰
I sniff the shell, I find the key,
I tuck it safely in a tree—erm, file🌿,
A name that hops from tab to tab,
Stable, small, with just one grab.
Terminal tales, in UUID style.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: introduction of cross-platform terminal identity generation. It is concise, specific, and clearly summarizes the primary purpose of the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jonah/omn-7295-terminal-identity

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
tests/unit/hooks/lib/test_terminal_identity.py (1)

10-19: Consider using proper package imports instead of sys.path manipulation.

Manual sys.path insertion is fragile and can cause import conflicts. If the hooks lib is a proper package, configure pyproject.toml or conftest.py to add it to the Python path during test discovery.

♻️ Alternative: conftest.py approach

In tests/conftest.py or a local conftest.py:

import sys
from pathlib import Path

# Add once at conftest level instead of per-test-file
sys.path.insert(0, str(Path(__file__).resolve().parents[3] / "plugins" / "onex" / "hooks" / "lib"))

Then the test file simplifies to:

-import sys
-from pathlib import Path
+from pathlib import Path
 
 import pytest
 
-# Add hooks/lib to path so we can import the module directly
-sys.path.insert(
-    0,
-    str(Path(__file__).resolve().parents[4] / "plugins" / "onex" / "hooks" / "lib"),
-)
-
-from terminal_identity import (  # noqa: E402
+from terminal_identity import (
     get_or_create_terminal_id,
     is_terminal_id_valid,
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/hooks/lib/test_terminal_identity.py` around lines 10 - 19, Replace
the per-test sys.path manipulation in
tests/unit/hooks/lib/test_terminal_identity.py by configuring imports at the
test-suite level: remove the sys.path.insert block and instead add the hooks/lib
path in tests/conftest.py (or via pyproject/pytest.ini import-path settings) so
the module terminal_identity can be imported normally; update the test to import
get_or_create_terminal_id and is_terminal_id_valid directly (no sys.path
changes) and ensure conftest computes the same Path used previously to locate
the plugins/onex/hooks/lib directory.
plugins/onex/hooks/lib/terminal_identity.py (1)

59-68: Consider adding error handling for file I/O.

File read/write operations (lines 60, 68) can fail due to permission issues, disk full, or concurrent access. Currently, exceptions would propagate unhandled.

For a "best-effort" utility, wrapping I/O in try/except and generating a fresh ID on failure would improve resilience.

♻️ Proposed resilient read/write
     if id_file.exists():
-        existing = id_file.read_text().strip()
-        if existing and is_terminal_id_valid(existing):
-            return existing
+        try:
+            existing = id_file.read_text().strip()
+            if existing and is_terminal_id_valid(existing):
+                return existing
+        except OSError:
+            pass  # Fall through to generate new ID
 
     hostname = platform.node().split(".")[0][:16]
     short_uuid = uuid.uuid4().hex[:8]
     terminal_id = f"terminal-{hostname}-{short_uuid}"
 
-    id_file.write_text(terminal_id)
+    try:
+        id_file.write_text(terminal_id)
+    except OSError:
+        pass  # ID still usable for this session even if not persisted
     return terminal_id
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/onex/hooks/lib/terminal_identity.py` around lines 59 - 68, The file
I/O for id_file.read_text() and id_file.write_text() can raise exceptions; wrap
the read and write operations in try/except (catch OSError/IOError or Exception)
around the existing id_file.exists() block and the write_text() call so that
read failures fall through to generate a new terminal_id and write failures do
not crash the process; ensure you still validate using
is_terminal_id_valid(existing) when read succeeds, return the generated
terminal_id even if write fails, and optionally log a warning (if a logger
exists) inside the except blocks to record the error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugins/onex/hooks/lib/terminal_identity.py`:
- Around line 32-40: The function _get_shell_key currently always returns
os.getppid(), but the docstring incorrectly claims Windows-specific "session
leader PID" behavior; update the docstring to state that _get_shell_key returns
the parent process ID (PPID) on all platforms (falling back to PID if PPID not
available) or, if you prefer to implement platform-specific behavior, replace
the body of _get_shell_key with Windows logic (e.g., using psutil to get the
session leader or Win32 APIs to derive the console/session leader PID) and keep
the docstring describing the implemented platform differences; reference the
function name _get_shell_key when making the change.

---

Nitpick comments:
In `@plugins/onex/hooks/lib/terminal_identity.py`:
- Around line 59-68: The file I/O for id_file.read_text() and
id_file.write_text() can raise exceptions; wrap the read and write operations in
try/except (catch OSError/IOError or Exception) around the existing
id_file.exists() block and the write_text() call so that read failures fall
through to generate a new terminal_id and write failures do not crash the
process; ensure you still validate using is_terminal_id_valid(existing) when
read succeeds, return the generated terminal_id even if write fails, and
optionally log a warning (if a logger exists) inside the except blocks to record
the error.

In `@tests/unit/hooks/lib/test_terminal_identity.py`:
- Around line 10-19: Replace the per-test sys.path manipulation in
tests/unit/hooks/lib/test_terminal_identity.py by configuring imports at the
test-suite level: remove the sys.path.insert block and instead add the hooks/lib
path in tests/conftest.py (or via pyproject/pytest.ini import-path settings) so
the module terminal_identity can be imported normally; update the test to import
get_or_create_terminal_id and is_terminal_id_valid directly (no sys.path
changes) and ensure conftest computes the same Path used previously to locate
the plugins/onex/hooks/lib directory.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: f3842f07-95a3-4d4a-8ad5-3cff9d20e0a8

📥 Commits

Reviewing files that changed from the base of the PR and between 7537b2a and 8500867.

📒 Files selected for processing (2)
  • plugins/onex/hooks/lib/terminal_identity.py
  • tests/unit/hooks/lib/test_terminal_identity.py

Comment thread plugins/onex/hooks/lib/terminal_identity.py
…implementation [OMN-7295]

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jonahgabriel
jonahgabriel enabled auto-merge April 2, 2026 15:36
@jonahgabriel
jonahgabriel added this pull request to the merge queue Apr 2, 2026
Merged via the queue into main with commit 8406d7d Apr 2, 2026
62 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-7295-terminal-identity branch April 2, 2026 15:50
jonahgabriel added a commit that referenced this pull request May 15, 2026
…e_core shim (SEAM-2)

Replaces the 450-line inline implementation with a thin shim that delegates
all logic to omnibase_core.validation.validator_skill_backing_node.

Public API re-exported for backward compat: load_allowlist, extract_backing_node,
check_node_liveness, scan, _omnimarket_available, _resolve_omnimarket_nodes_root.
NodeViolation alias preserved for validate_skill_aspiration.py.

BLOCKED ON: omnibase_core PR #1069 (feat(OMN-10171)) must merge and version bump
before this PR can merge. omniclaude pins omnibase-core==0.40.1; the new module
omnibase_core.validation.validator_skill_backing_node is not in that version.
After omnibase_core publishes, update the pin and merge this PR.
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