rootsign 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. rootsign-0.1.1/.env.example +38 -0
  2. rootsign-0.1.1/.github/CLA_SIGNED.md +7 -0
  3. rootsign-0.1.1/.github/CODEOWNERS +9 -0
  4. rootsign-0.1.1/.github/ISSUE_TEMPLATE/bug_report.yml +33 -0
  5. rootsign-0.1.1/.github/ISSUE_TEMPLATE/feature_request.yml +34 -0
  6. rootsign-0.1.1/.github/ISSUE_TEMPLATE/framework_integration.yml +26 -0
  7. rootsign-0.1.1/.github/PULL_REQUEST_TEMPLATE.md +27 -0
  8. rootsign-0.1.1/.github/workflows/ci.yml +153 -0
  9. rootsign-0.1.1/.gitignore +65 -0
  10. rootsign-0.1.1/.vscode/settings.json +9 -0
  11. rootsign-0.1.1/CLA.md +15 -0
  12. rootsign-0.1.1/CLAUDE.md +90 -0
  13. rootsign-0.1.1/CONTRIBUTING.md +82 -0
  14. rootsign-0.1.1/CONTRIBUTORS.md +11 -0
  15. rootsign-0.1.1/LICENSE +201 -0
  16. rootsign-0.1.1/NOTICE +10 -0
  17. rootsign-0.1.1/PKG-INFO +313 -0
  18. rootsign-0.1.1/README.md +267 -0
  19. rootsign-0.1.1/SECURITY.md +65 -0
  20. rootsign-0.1.1/alembic.ini +39 -0
  21. rootsign-0.1.1/docker-compose.yml +22 -0
  22. rootsign-0.1.1/docs/adr/ADR-001-hash-canonical-spec.md +60 -0
  23. rootsign-0.1.1/docs/adr/ADR-002-transport-agnostic-client.md +47 -0
  24. rootsign-0.1.1/docs/adr/ADR-003-framework-contract-tests.md +39 -0
  25. rootsign-0.1.1/docs/adr/ADR-004-langgraph-interception-strategy.md +113 -0
  26. rootsign-0.1.1/docs/adr/ADR-005-crewai-interception-strategy.md +117 -0
  27. rootsign-0.1.1/docs/adr/ADR-006-redaction-contract.md +158 -0
  28. rootsign-0.1.1/docs/adr/ADR-007-hitl-checkpoint-design.md +214 -0
  29. rootsign-0.1.1/docs/adr/ADR-008-decision-capture.md +84 -0
  30. rootsign-0.1.1/docs/design-partner-feedback.md +180 -0
  31. rootsign-0.1.1/docs/framework-support.md +104 -0
  32. rootsign-0.1.1/docs/releases/v0.1.0.md +129 -0
  33. rootsign-0.1.1/docs/rootsign-logo.png +0 -0
  34. rootsign-0.1.1/docs/show-hn-draft.md +178 -0
  35. rootsign-0.1.1/pyproject.toml +102 -0
  36. rootsign-0.1.1/rootsign/__init__.py +106 -0
  37. rootsign-0.1.1/rootsign/_migrations/__init__.py +7 -0
  38. rootsign-0.1.1/rootsign/_migrations/env.py +65 -0
  39. rootsign-0.1.1/rootsign/_migrations/script.py.mako +25 -0
  40. rootsign-0.1.1/rootsign/_migrations/versions/0001_initial_schema.py +387 -0
  41. rootsign-0.1.1/rootsign/_migrations/versions/0002_approval_parent_id.py +56 -0
  42. rootsign-0.1.1/rootsign/_migrations/versions/0003_action_timed_out.py +50 -0
  43. rootsign-0.1.1/rootsign/_version.py +29 -0
  44. rootsign-0.1.1/rootsign/cli.py +230 -0
  45. rootsign-0.1.1/rootsign/config.py +32 -0
  46. rootsign-0.1.1/rootsign/crud/__init__.py +28 -0
  47. rootsign-0.1.1/rootsign/crud/action.py +201 -0
  48. rootsign-0.1.1/rootsign/crud/agent.py +10 -0
  49. rootsign-0.1.1/rootsign/crud/approval.py +298 -0
  50. rootsign-0.1.1/rootsign/crud/base.py +74 -0
  51. rootsign-0.1.1/rootsign/crud/decision.py +39 -0
  52. rootsign-0.1.1/rootsign/crud/incident.py +10 -0
  53. rootsign-0.1.1/rootsign/crud/policy.py +10 -0
  54. rootsign-0.1.1/rootsign/crud/session.py +10 -0
  55. rootsign-0.1.1/rootsign/database.py +32 -0
  56. rootsign-0.1.1/rootsign/errors.py +173 -0
  57. rootsign-0.1.1/rootsign/hashing.py +47 -0
  58. rootsign-0.1.1/rootsign/ingest/__init__.py +19 -0
  59. rootsign-0.1.1/rootsign/ingest/handler.py +351 -0
  60. rootsign-0.1.1/rootsign/ingest/idempotency.py +66 -0
  61. rootsign-0.1.1/rootsign/ingest/schemas.py +203 -0
  62. rootsign-0.1.1/rootsign/models/__init__.py +19 -0
  63. rootsign-0.1.1/rootsign/models/action.py +86 -0
  64. rootsign-0.1.1/rootsign/models/agent.py +66 -0
  65. rootsign-0.1.1/rootsign/models/approval.py +66 -0
  66. rootsign-0.1.1/rootsign/models/decision.py +61 -0
  67. rootsign-0.1.1/rootsign/models/incident.py +62 -0
  68. rootsign-0.1.1/rootsign/models/policy.py +50 -0
  69. rootsign-0.1.1/rootsign/models/session.py +63 -0
  70. rootsign-0.1.1/rootsign/schemas/__init__.py +83 -0
  71. rootsign-0.1.1/rootsign/schemas/action.py +57 -0
  72. rootsign-0.1.1/rootsign/schemas/agent.py +66 -0
  73. rootsign-0.1.1/rootsign/schemas/approval.py +42 -0
  74. rootsign-0.1.1/rootsign/schemas/decision.py +34 -0
  75. rootsign-0.1.1/rootsign/schemas/incident.py +62 -0
  76. rootsign-0.1.1/rootsign/schemas/policy.py +48 -0
  77. rootsign-0.1.1/rootsign/schemas/session.py +50 -0
  78. rootsign-0.1.1/rootsign/sdk/__init__.py +40 -0
  79. rootsign-0.1.1/rootsign/sdk/_async_bridge.py +50 -0
  80. rootsign-0.1.1/rootsign/sdk/chain.py +151 -0
  81. rootsign-0.1.1/rootsign/sdk/cli.py +300 -0
  82. rootsign-0.1.1/rootsign/sdk/client.py +107 -0
  83. rootsign-0.1.1/rootsign/sdk/config.py +78 -0
  84. rootsign-0.1.1/rootsign/sdk/context.py +127 -0
  85. rootsign-0.1.1/rootsign/sdk/decorator.py +612 -0
  86. rootsign-0.1.1/rootsign/sdk/frameworks/__init__.py +6 -0
  87. rootsign-0.1.1/rootsign/sdk/frameworks/crewai.py +154 -0
  88. rootsign-0.1.1/rootsign/sdk/frameworks/langgraph.py +125 -0
  89. rootsign-0.1.1/rootsign/sdk/hashing.py +42 -0
  90. rootsign-0.1.1/rootsign/sdk/hitl.py +231 -0
  91. rootsign-0.1.1/rootsign/sdk/redaction.py +228 -0
  92. rootsign-0.1.1/rootsign/sdk/registration.py +73 -0
  93. rootsign-0.1.1/rootsign/sdk/session.py +119 -0
  94. rootsign-0.1.1/scripts/demo_verify_chain.py +125 -0
  95. rootsign-0.1.1/scripts/generate_hash_vectors.py +114 -0
  96. rootsign-0.1.1/scripts/init_test_db.sql +5 -0
  97. rootsign-0.1.1/tests/__init__.py +0 -0
  98. rootsign-0.1.1/tests/conftest.py +304 -0
  99. rootsign-0.1.1/tests/contract/__init__.py +0 -0
  100. rootsign-0.1.1/tests/contract/crewai/__init__.py +0 -0
  101. rootsign-0.1.1/tests/contract/crewai/test_tool_interception.py +170 -0
  102. rootsign-0.1.1/tests/contract/langgraph/__init__.py +1 -0
  103. rootsign-0.1.1/tests/contract/langgraph/test_tool_interception.py +153 -0
  104. rootsign-0.1.1/tests/fixtures/hash_vectors.json +60 -0
  105. rootsign-0.1.1/tests/fixtures/redaction_vectors.json +47 -0
  106. rootsign-0.1.1/tests/integration/__init__.py +0 -0
  107. rootsign-0.1.1/tests/integration/test_approve_cli.py +229 -0
  108. rootsign-0.1.1/tests/integration/test_crewai_integration.py +129 -0
  109. rootsign-0.1.1/tests/integration/test_crud.py +306 -0
  110. rootsign-0.1.1/tests/integration/test_decision_capture.py +200 -0
  111. rootsign-0.1.1/tests/integration/test_decision_ingest.py +69 -0
  112. rootsign-0.1.1/tests/integration/test_ingest.py +737 -0
  113. rootsign-0.1.1/tests/integration/test_langgraph_integration.py +130 -0
  114. rootsign-0.1.1/tests/integration/test_register_agent.py +66 -0
  115. rootsign-0.1.1/tests/integration/test_relationships.py +130 -0
  116. rootsign-0.1.1/tests/integration/test_sdk_smoke.py +106 -0
  117. rootsign-0.1.1/tests/integration/test_session_context_manager.py +64 -0
  118. rootsign-0.1.1/tests/integration/test_show_hn_quickstart.py +186 -0
  119. rootsign-0.1.1/tests/integration/test_verify_cli.py +154 -0
  120. rootsign-0.1.1/tests/performance/__init__.py +0 -0
  121. rootsign-0.1.1/tests/performance/test_benchmarks.py +125 -0
  122. rootsign-0.1.1/tests/performance/test_langgraph_benchmarks.py +73 -0
  123. rootsign-0.1.1/tests/performance/test_verify_benchmarks.py +108 -0
  124. rootsign-0.1.1/tests/unit/__init__.py +0 -0
  125. rootsign-0.1.1/tests/unit/test_action_record_decision_id.py +118 -0
  126. rootsign-0.1.1/tests/unit/test_chain.py +166 -0
  127. rootsign-0.1.1/tests/unit/test_context.py +125 -0
  128. rootsign-0.1.1/tests/unit/test_crewai_tracer.py +184 -0
  129. rootsign-0.1.1/tests/unit/test_crud_approval.py +277 -0
  130. rootsign-0.1.1/tests/unit/test_emit_approval_record.py +206 -0
  131. rootsign-0.1.1/tests/unit/test_emit_decision_record.py +163 -0
  132. rootsign-0.1.1/tests/unit/test_errors.py +127 -0
  133. rootsign-0.1.1/tests/unit/test_hashing.py +189 -0
  134. rootsign-0.1.1/tests/unit/test_hitl.py +298 -0
  135. rootsign-0.1.1/tests/unit/test_ingest_client.py +85 -0
  136. rootsign-0.1.1/tests/unit/test_langgraph_tracer.py +144 -0
  137. rootsign-0.1.1/tests/unit/test_redaction.py +68 -0
  138. rootsign-0.1.1/tests/unit/test_redaction_pii.py +270 -0
  139. rootsign-0.1.1/tests/unit/test_schemas.py +294 -0
  140. rootsign-0.1.1/tests/unit/test_sdk_config.py +51 -0
  141. rootsign-0.1.1/tests/unit/test_sdk_hashing.py +52 -0
  142. rootsign-0.1.1/tests/unit/test_trace_hitl.py +372 -0
  143. rootsign-0.1.1/uv.lock +4496 -0
@@ -0,0 +1,38 @@
1
+ # ---------------------------------------------------------------------------
2
+ # Store-side infra config (read by rootsign.config.Settings — no prefix).
3
+ # These describe the PostgreSQL/TimescaleDB instance the storage layer
4
+ # connects to. Defaults assume the bundled docker-compose db service.
5
+ # ---------------------------------------------------------------------------
6
+ DATABASE_URL=postgresql+asyncpg://rootsign:rootsign@localhost:5432/rootsign_dev
7
+ DATABASE_URL_SYNC=postgresql+psycopg2://rootsign:rootsign@localhost:5432/rootsign_dev
8
+ TEST_DATABASE_URL=postgresql+asyncpg://rootsign:rootsign@localhost:5432/rootsign_test
9
+ TEST_DATABASE_URL_SYNC=postgresql+psycopg2://rootsign:rootsign@localhost:5432/rootsign_test
10
+ DB_POOL_SIZE=10
11
+ DB_MAX_OVERFLOW=20
12
+ DB_POOL_TIMEOUT=30
13
+
14
+ # ---------------------------------------------------------------------------
15
+ # RootSign SDK config (read by rootsign.sdk.config.SDKSettings, prefix
16
+ # ROOTSIGN_). User-facing — the developer using @rootsign.trace sets these.
17
+ # ---------------------------------------------------------------------------
18
+
19
+ # Transport: 'local' calls IngestHandler in-process (Phase 1 default).
20
+ # 'cloud' would POST to the hosted backend, but Phase 1 stubs that path —
21
+ # HttpIngestClient raises NotImplementedError until Phase 2.
22
+ ROOTSIGN_BACKEND=local
23
+ # ROOTSIGN_CLOUD_URL=https://ingest.getprovidex.com/v1
24
+ # ROOTSIGN_API_KEY=your-api-key-here
25
+
26
+ # Capture per-step Decision records (the agent's reasoning). Off by default
27
+ # because Decision payloads are the largest and most PII-sensitive surface.
28
+ # Enabling in production requires explicit user-consent acknowledgement.
29
+ ROOTSIGN_CAPTURE_DECISIONS=false
30
+
31
+ # Write-ahead log for events that failed ingest (network blip, DB down).
32
+ # The decorator drains this on the next successful call. Default: ~/.rootsign/wal
33
+ ROOTSIGN_WAL_PATH=~/.rootsign/wal
34
+
35
+ # Retry policy for HttpIngestClient (Phase 2 — unused in Phase 1).
36
+ ROOTSIGN_MAX_RETRIES=3
37
+ ROOTSIGN_RETRY_BASE_DELAY=0.1
38
+ ROOTSIGN_RETRY_MAX_DELAY=5.0
@@ -0,0 +1,7 @@
1
+ # CLA Signatures
2
+
3
+ This file records contributors who have signed the [Contributor License Agreement](../CLA.md). New contributors are added automatically by the CLA Assistant bot the first time they comment the sign-off line on a PR.
4
+
5
+ | GitHub handle | Date | Commit |
6
+ |---------------|------------|---------|
7
+ | @oabolade | 2026-05-01 | initial |
@@ -0,0 +1,9 @@
1
+ # RootSign CODEOWNERS
2
+ # These owners are automatically requested for review on PRs.
3
+
4
+ * @oabolade
5
+ /rootsign/ @oabolade
6
+ /tests/ @oabolade
7
+ /docs/adr/ @oabolade
8
+ /alembic/ @oabolade
9
+ /.github/ @oabolade
@@ -0,0 +1,33 @@
1
+ name: Bug report
2
+ description: Something is not working as described in the spec
3
+ labels: [bug, needs-triage]
4
+ body:
5
+ - type: textarea
6
+ id: description
7
+ attributes:
8
+ label: What happened?
9
+ description: Describe the bug. Include the exact error message.
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: repro
14
+ attributes:
15
+ label: Minimal reproduction
16
+ description: Shortest code that reproduces the issue.
17
+ render: python
18
+ validations:
19
+ required: true
20
+ - type: dropdown
21
+ id: framework
22
+ attributes:
23
+ label: Agent framework
24
+ options: [LangGraph, CrewAI, AutoGen, Custom, Not applicable]
25
+ validations:
26
+ required: true
27
+ - type: input
28
+ id: versions
29
+ attributes:
30
+ label: Versions
31
+ placeholder: rootsign==0.1.0, langgraph==0.2.1, python==3.11
32
+ validations:
33
+ required: true
@@ -0,0 +1,34 @@
1
+ name: Feature request
2
+ description: Suggest a new capability or improvement
3
+ labels: [enhancement, needs-triage]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: What problem does this solve?
9
+ description: Describe the limitation or gap you are experiencing.
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: solution
14
+ attributes:
15
+ label: Proposed solution
16
+ description: How would you like this to work?
17
+ validations:
18
+ required: true
19
+ - type: dropdown
20
+ id: phase
21
+ attributes:
22
+ label: Which product phase does this relate to?
23
+ options:
24
+ - Phase 1 (SDK capture)
25
+ - Phase 2 (Compliance dashboard)
26
+ - Phase 3 (Enterprise enforcement)
27
+ - Phase 4 (Cross-platform governance)
28
+ - Not sure
29
+ - type: checkboxes
30
+ id: contribute
31
+ attributes:
32
+ label: Contribution
33
+ options:
34
+ - label: I am willing to implement this
@@ -0,0 +1,26 @@
1
+ name: Framework integration request
2
+ description: Request support for a new agent framework
3
+ labels: [framework-integration, enhancement]
4
+ body:
5
+ - type: input
6
+ id: framework
7
+ attributes:
8
+ label: Framework name and link
9
+ placeholder: 'LlamaIndex — https://github.com/run-llama/llama_index'
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: tool_call
14
+ attributes:
15
+ label: How does this framework call tools?
16
+ description: Paste a minimal example of a tool call in this framework.
17
+ render: python
18
+ validations:
19
+ required: true
20
+ - type: checkboxes
21
+ id: willing
22
+ attributes:
23
+ label: Contribution
24
+ options:
25
+ - label: I am willing to implement this integration
26
+ - label: I can provide a real pipeline for contract testing
@@ -0,0 +1,27 @@
1
+ ## Summary
2
+ <!-- One sentence: what does this PR do? -->
3
+
4
+ ## Related issue
5
+ Closes #
6
+
7
+ ## Type of change
8
+ - [ ] Bug fix
9
+ - [ ] New feature
10
+ - [ ] Framework integration
11
+ - [ ] Documentation
12
+ - [ ] Test coverage
13
+
14
+ ## Checklist
15
+ - [ ] All existing tests pass (`pytest tests/ -v`)
16
+ - [ ] New code has test coverage >= 90%
17
+ - [ ] Overall coverage stays >= 85% (enforced by `pyproject.toml`)
18
+ - [ ] No changes to canonical hash spec (or new ADR filed if yes — see [ADR-001](../docs/adr/ADR-001-hash-canonical-spec.md))
19
+ - [ ] `ruff check .` and `ruff format .` pass
20
+ - [ ] CONTRIBUTING.md commit message format followed
21
+ - [ ] CLA signed (bot will check automatically)
22
+
23
+ ## Testing done
24
+ <!-- List specific test cases you ran manually -->
25
+
26
+ ## Notes for reviewer
27
+ <!-- Anything the reviewer should pay special attention to -->
@@ -0,0 +1,153 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, 'feat/**', 'fix/**', 'test/**', 'docs/**']
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ unit-tests:
11
+ name: Unit tests (Python ${{ matrix.python-version }})
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version: ['3.11', '3.12']
17
+ services:
18
+ # The session-scoped _bootstrap_test_db fixture needs a real Postgres
19
+ # even for unit tests (it runs alembic against rootsign_test before
20
+ # collection). See feedback_phase0_discrepancies — we keep the
21
+ # alembic-based test DB rather than Base.metadata.create_all so the
22
+ # actions table stays a real TimescaleDB hypertable.
23
+ timescaledb:
24
+ image: timescale/timescaledb:latest-pg16
25
+ env:
26
+ POSTGRES_DB: rootsign_dev
27
+ POSTGRES_USER: rootsign
28
+ POSTGRES_PASSWORD: rootsign
29
+ ports: ['5432:5432']
30
+ options: >-
31
+ --health-cmd pg_isready
32
+ --health-interval 5s
33
+ --health-timeout 5s
34
+ --health-retries 10
35
+ env:
36
+ DATABASE_URL: postgresql+asyncpg://rootsign:rootsign@localhost:5432/rootsign_dev
37
+ DATABASE_URL_SYNC: postgresql+psycopg2://rootsign:rootsign@localhost:5432/rootsign_dev
38
+ TEST_DATABASE_URL: postgresql+asyncpg://rootsign:rootsign@localhost:5432/rootsign_test
39
+ TEST_DATABASE_URL_SYNC: postgresql+psycopg2://rootsign:rootsign@localhost:5432/rootsign_test
40
+ steps:
41
+ - uses: actions/checkout@v5
42
+ - uses: actions/setup-python@v6
43
+ with:
44
+ python-version: ${{ matrix.python-version }}
45
+ - name: Install
46
+ run: pip install -e '.[dev]'
47
+ - name: Wait for Postgres
48
+ run: |
49
+ for _ in $(seq 1 30); do
50
+ pg_isready -h localhost -U rootsign -d rootsign_dev && break
51
+ sleep 1
52
+ done
53
+ - name: Bootstrap rootsign_test
54
+ run: |
55
+ PGPASSWORD=rootsign psql -h localhost -U rootsign -d rootsign_dev \
56
+ -c "CREATE DATABASE rootsign_test OWNER rootsign;" || true
57
+ PGPASSWORD=rootsign psql -h localhost -U rootsign -d rootsign_test \
58
+ -c "CREATE EXTENSION IF NOT EXISTS timescaledb;"
59
+ - name: Unit tests
60
+ run: pytest tests/unit/ -v
61
+
62
+ integration-tests:
63
+ name: Integration tests (Python 3.12)
64
+ runs-on: ubuntu-latest
65
+ services:
66
+ timescaledb:
67
+ image: timescale/timescaledb:latest-pg16
68
+ env:
69
+ POSTGRES_DB: rootsign_dev
70
+ POSTGRES_USER: rootsign
71
+ POSTGRES_PASSWORD: rootsign
72
+ ports: ['5432:5432']
73
+ options: >-
74
+ --health-cmd pg_isready
75
+ --health-interval 5s
76
+ --health-timeout 5s
77
+ --health-retries 10
78
+ env:
79
+ DATABASE_URL: postgresql+asyncpg://rootsign:rootsign@localhost:5432/rootsign_dev
80
+ DATABASE_URL_SYNC: postgresql+psycopg2://rootsign:rootsign@localhost:5432/rootsign_dev
81
+ TEST_DATABASE_URL: postgresql+asyncpg://rootsign:rootsign@localhost:5432/rootsign_test
82
+ TEST_DATABASE_URL_SYNC: postgresql+psycopg2://rootsign:rootsign@localhost:5432/rootsign_test
83
+ steps:
84
+ - uses: actions/checkout@v5
85
+ - uses: actions/setup-python@v6
86
+ with:
87
+ python-version: '3.12'
88
+ - run: pip install -e '.[dev]'
89
+ - name: Bootstrap rootsign_test
90
+ run: |
91
+ PGPASSWORD=rootsign psql -h localhost -U rootsign -d rootsign_dev \
92
+ -c "CREATE DATABASE rootsign_test OWNER rootsign;" || true
93
+ PGPASSWORD=rootsign psql -h localhost -U rootsign -d rootsign_test \
94
+ -c "CREATE EXTENSION IF NOT EXISTS timescaledb;"
95
+ - name: alembic upgrade head
96
+ run: alembic upgrade head
97
+ - name: Integration tests
98
+ run: pytest tests/integration/ -v
99
+
100
+ framework-contract-langgraph:
101
+ # ADR-003 / Sprint 2: framework contract tests are MANDATORY — this job
102
+ # must pass on every PR before merge. Sprint 2 filled the contract suite
103
+ # in tests/contract/langgraph/ (see ADR-004 for the interception design).
104
+ #
105
+ # Contract tests use a mock IngestClient and never touch the DB, so this
106
+ # job intentionally runs WITHOUT a Postgres service. The
107
+ # ROOTSIGN_SKIP_DB_BOOTSTRAP env var tells the session-autouse fixture
108
+ # in tests/conftest.py to skip alembic / DB connect at session start.
109
+ name: LangGraph contract (langgraph ~=${{ matrix.langgraph-version }})
110
+ runs-on: ubuntu-latest
111
+ strategy:
112
+ fail-fast: false
113
+ matrix:
114
+ langgraph-version: ['0.1', '0.2']
115
+ env:
116
+ ROOTSIGN_SKIP_DB_BOOTSTRAP: '1'
117
+ steps:
118
+ - uses: actions/checkout@v5
119
+ - uses: actions/setup-python@v6
120
+ with:
121
+ python-version: '3.12'
122
+ - name: Install with langgraph extra
123
+ run: pip install -e '.[dev,langgraph]' "langgraph~=${{ matrix.langgraph-version }}"
124
+ - name: Contract tests
125
+ run: pytest tests/contract/langgraph/ -v
126
+
127
+ framework-contract-crewai:
128
+ # ADR-005 / Sprint 3: framework contract tests for CrewAI are MANDATORY —
129
+ # this job must pass on every PR before merge. Same pattern as the
130
+ # langgraph job above: mock IngestClient, no DB, ROOTSIGN_SKIP_DB_BOOTSTRAP.
131
+ #
132
+ # Sprint 4 (S4-TASK 10): added '1.0' to lock the duck-typing strategy
133
+ # against the 1.x line ahead of the Show HN post. Local run against
134
+ # crewai 1.6.1 had all 13 contract tests green — the ADR-005
135
+ # heuristic (name + _run callable) survives 1.x's BaseTool refactor
136
+ # because we never imported the class, only the shape.
137
+ name: CrewAI contract (crewai ~=${{ matrix.crewai-version }})
138
+ runs-on: ubuntu-latest
139
+ strategy:
140
+ fail-fast: false
141
+ matrix:
142
+ crewai-version: ['0.28', '0.40', '1.0']
143
+ env:
144
+ ROOTSIGN_SKIP_DB_BOOTSTRAP: '1'
145
+ steps:
146
+ - uses: actions/checkout@v5
147
+ - uses: actions/setup-python@v6
148
+ with:
149
+ python-version: '3.12'
150
+ - name: Install with crewai extra
151
+ run: pip install -e '.[dev,crewai]' "crewai~=${{ matrix.crewai-version }}"
152
+ - name: Contract tests
153
+ run: pytest tests/contract/crewai/ -v
@@ -0,0 +1,65 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.so
5
+ .Python
6
+ .venv/
7
+ venv/
8
+ env/
9
+ *.egg-info/
10
+ *.egg
11
+ dist/
12
+ build/
13
+ .eggs/
14
+ .pytest_cache/
15
+ .coverage
16
+ .coverage.*
17
+ htmlcov/
18
+ coverage.xml
19
+ .tox/
20
+ .mypy_cache/
21
+ .ruff_cache/
22
+ .dmypy.json
23
+ .env
24
+ .env.local
25
+ .idea/
26
+ # .vscode: gitignore everything except shared workspace files
27
+ .vscode/*
28
+ !.vscode/settings.json
29
+ !.vscode/extensions.json
30
+ !.vscode/tasks.json
31
+ *.swp
32
+ *.swo
33
+ .DS_Store
34
+ *.log
35
+ pip-log.txt
36
+ pip-delete-this-directory.txt
37
+ .python-version
38
+
39
+ # Confidential coding-agent sprint briefings (per CLAUDE.md / memory
40
+ # feedback_never_commit_internal_specs). These are dropped into the
41
+ # repo root for the coding agent to READ but must NEVER be committed.
42
+ # Memory reference: feedback_never_commit_internal_specs.md.
43
+ AGENTS_Phase*.md
44
+ AGENTS_PRD*.md
45
+ RootSign_Phase*.docx
46
+ RootSign_Phase*.md
47
+ RootSign_PRD*.docx
48
+ RootSign_PRD*.md
49
+ ProvidexAI_Phase*.docx
50
+ ProvidexAI_Phase*.md
51
+ ProvidexAI_PRD*.docx
52
+ ProvidexAI_PRD*.md
53
+
54
+ # Code-quality / security review artifacts the founder runs locally.
55
+ # Track them in a private notes location, not in-tree.
56
+ rootsign_review.md
57
+
58
+ # Local-only memory backups and ephemeral sample files dropped into the
59
+ # repo root for the coding agent to read during a session. See CLAUDE.md
60
+ # top section. MEMORY.md is the working memory index — never committed.
61
+ MEMORY.md
62
+ MEMORY_*.md
63
+ Sample_*.md
64
+ Sample_*.py
65
+ Sample_*.docx
@@ -0,0 +1,9 @@
1
+ {
2
+ "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
3
+ "python.testing.pytestEnabled": true,
4
+ "python.testing.unittestEnabled": false,
5
+ "python.testing.pytestArgs": ["tests"],
6
+ "[python]": {
7
+ "editor.defaultFormatter": "charliermarsh.ruff"
8
+ }
9
+ }
rootsign-0.1.1/CLA.md ADDED
@@ -0,0 +1,15 @@
1
+ # RootSign Contributor License Agreement
2
+
3
+ By signing this agreement, you (the Contributor) grant Providex AI Inc. (the Project) a perpetual, worldwide, non-exclusive, royalty-free license to use, reproduce, modify, distribute, and sublicense your Contributions as part of the Project.
4
+
5
+ You confirm that:
6
+
7
+ 1. You have the legal right to grant this license.
8
+ 2. Your Contribution is your original work, or you have sufficient rights to submit it.
9
+ 3. You understand the Project may relicense your Contribution under other terms in the future, including commercial licenses.
10
+
11
+ You retain copyright ownership of your Contributions.
12
+
13
+ This agreement does not affect your ability to use your own Contributions for any purpose.
14
+
15
+ **To sign:** comment `I have read the CLA Document and I hereby sign the CLA` on any pull request. The CLA Assistant bot will record your signature.
@@ -0,0 +1,90 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## NEVER commit or push project/sprint artifacts
6
+
7
+ Sprint plans, agent guides, internal audits, memory snapshots, and similar working documents **must stay local**. They are gitignored as a backstop, but the rule is the rule regardless of whether `.gitignore` catches a given filename:
8
+
9
+ - `AGENTS*.md`, `AGENTS_Phase*.md`, `RootSign_Phase*.{md,docx}`, `ProvidexAI_Phase*.{md,docx}`
10
+ - `MEMORY.md` and anything under a `memory/` directory
11
+ - `rootsign_review.md` and other founder-run audit artifacts
12
+
13
+ If a new artifact like this gets created during a session, treat it as local-only by default. Do not `git add`, do not stage, do not include in commits. If a `git add -A` / `git add .` would sweep one in, switch to per-file staging. If a similar file pattern appears that isn't already gitignored, add the pattern to `.gitignore` in the same change.
14
+
15
+ **Why:** these documents contain unreleased product strategy, audit findings, and pre-decision context. A Sprint 4 history-rewrite was needed once to scrub an accidentally-tracked sprint plan — the gitignore patterns added in commit 128cec5 exist as a mechanical backstop. The rule is to never need that backstop.
16
+
17
+ ## Where the code actually lives
18
+
19
+ The Python project is `phase0/` (this directory). The parent `turbo/` is just a workspace wrapper. All paths below are relative to `phase0/`.
20
+
21
+ ## Dev environment
22
+
23
+ CONTRIBUTING.md has the full setup. The non-obvious bits:
24
+
25
+ - **Always run `python -m pytest`, never bare `pytest`.** A brew-installed `pytest` shadows the venv binary and silently runs under the system interpreter — produces `ModuleNotFoundError: sqlalchemy` and similar.
26
+ - **Even unit tests need a running database.** `tests/conftest.py` has a session-scoped `_bootstrap_test_db` fixture that runs alembic before any test collection. Start the DB first: `rootsign-admin start-db` (or `docker-compose up -d db` in-repo).
27
+ - **Schema bootstrap:** `rootsign-admin init` applies migrations. Idempotent. `--reset` drops and recreates the public schema (no confirmation prompt — be careful).
28
+ - **Single test:** `python -m pytest tests/integration/test_show_hn_quickstart.py::TestShowHNQuickstart::test_readme_quickstart_end_to_end -v`
29
+ - **Test markers:** `integration` and `benchmark` are declared in `pyproject.toml`. Performance suite at `tests/performance/` is opt-in via `-m benchmark`.
30
+ - **Coverage gate:** `fail_under = 85` in `pyproject.toml`. CI enforces it. New code expected at ≥90% per CONTRIBUTING.
31
+ - **Lint:** `ruff check .` and `ruff format .` before pushing.
32
+
33
+ ## Two CLIs — do not flip them
34
+
35
+ Naming is locked (sprint plan Flag, do not re-derive):
36
+
37
+ | Surface | Entry point | Commands |
38
+ |---|---|---|
39
+ | **User CLI** `rootsign` | `rootsign.sdk.cli:app` | `verify`, `approve`, `approve --list` |
40
+ | **Operator CLI** `rootsign-admin` | `rootsign.cli:app` | `start-db`, `stop-db`, `init`, `status` |
41
+
42
+ `rootsign approve <id>` is a developer workflow on the user CLI. `rootsign-admin replay-pending` (when it lands) is a privileged schema-level operation on the operator CLI. Decorator is `@rootsign.trace`, never `@providex.trace`. Package is `rootsign`, never `providex`.
43
+
44
+ ## Big-picture architecture
45
+
46
+ **Hash chain (per-session, tamper-evident).** Each `Action` row carries `prev_action_hash` linking to the previous action in its session. `compute_action_self_hash` in `rootsign/hashing.py` is the **frozen canonical spec** — ADR-001 governs it, and CONTRIBUTING refuses to merge changes without a new ADR. Never re-implement it (the local-verify path got this wrong once and silently broke; see commit 128cec5). `self_hash` deliberately excludes `input_redacted`/`output_redacted` — the chain proves hash integrity, not payload-to-hash binding (an open pre-Phase-2 audit item).
47
+
48
+ **Ingest path.** SDK constructs an envelope → `IngestClient.handle(envelope)` → `IngestHandler` validates and routes by `event_type` → CRUD writes. `LocalIngestClient` is the in-process v0.1.0 path. `HttpIngestClient` is the Phase 2 hosted-backend path. Failure isolation rule (ADR-002): ingest **never raises into the decorated tool**; failures log at WARNING and the tool returns normally.
49
+
50
+ **HiTL checkpoint (ADR-007 — locked design).** `require_approval=True` on `@rootsign.trace` inserts an `ACTION_RECORD` with `authorization_status='pending'` and a reserved sequence number at submission time, then waits on `HiTLCheckpoint` (async poll loop). On approval: tool runs. Timeout: status becomes `'timed_out'` (terminal, distinct from `'human_rejected'`) and an Approval row is written with `approver_type='timeout_auto_rejected'`. **APPROVAL_RECORD rows are NOT in the hash chain** — they're a separate entity queried independently. The poll loop opens its own `AsyncSession` per cycle (`session_factory=AsyncSessionLocal`), never the caller's.
51
+
52
+ **Storage.** PostgreSQL 16 + TimescaleDB 2.x. The `actions` table is a **hypertable partitioned by `timestamp`**, which has hard consequences for any code joining against it (see below).
53
+
54
+ **Migrations.** Live in `rootsign/_migrations/` so they ship inside the wheel. `rootsign-admin init` resolves the directory via `importlib.resources.files("rootsign") / "_migrations"` and builds `alembic.config.Config` programmatically — no `alembic.ini` lookup, no cwd assumption. Developers running `alembic` directly from repo root work via the root-level `alembic.ini` whose `script_location` points at the same directory.
55
+
56
+ ## Test invariants (binding rules)
57
+
58
+ These were locked in the Sprint 3/4 plans because each one traces to a specific incident. Audit any new SDK or test code against them.
59
+
60
+ 1. **`_emit_action_record` and `_emit_approval_record` are keyword-only.** No positional args.
61
+ 2. **AsyncSession loop binding:**
62
+ - Tool calls in async tests use `await tool.ainvoke({...})` — never `tool._run(...)` or sync `tool.invoke(...)`.
63
+ - CLI tests in async use `await asyncio.to_thread(runner.invoke, app, [...])` — never bare `runner.invoke(...)`. Typer's runner does `asyncio.run()` internally and crashes inside an already-running loop.
64
+ 3. **`seeded_agent` (commits) for HiTL / CLI / `asyncio.to_thread` tests.** `registered_agent` uses SAVEPOINT rollback — its data is invisible to the poll loop's per-cycle session, the `to_thread` CLI runner, and the timeout recorder.
65
+ 4. **HiTL design is locked (ADR-007).** Don't re-derive it in code.
66
+ 5. **Hypertable-safe Action lookups.** Single-column `action_id` lookups are forbidden. Two valid two-column forms:
67
+ - `(action_id, action_timestamp)` — canonical chain-link form (`CRUDApproval.create_with_chain_link`, HiTL CLI / poll-loop paths). Prunes chunks on the partition column.
68
+ - `(session_id, action_id)` — `CRUDApproval.create_with_action_status_update` (ingest path). `ApprovalRecordPayload` doesn't carry `action_timestamp`; switching would require an envelope-schema bump.
69
+ 6. **`tests/integration/test_show_hn_quickstart.py` is the launch gate.** It mirrors the README's LangGraph quickstart end-to-end (register → instrument → verify) and must stay green.
70
+
71
+ ## What's deliberately orphaned
72
+
73
+ - **`_emit_approval_record`** in `rootsign/sdk/decorator.py` has zero call sites in `rootsign/`. It's a Phase 2 hook for when `HttpIngestClient` lands — the v0.1.0 HiTL CLI writes APPROVAL_RECORD rows directly via `CRUDApproval.create_with_chain_link` (single source of truth). Re-emitting via the IngestClient path would hit the terminal-state guard and warn for no semantic gain. The marker comment above the def points at this; don't delete the helper or its tests.
74
+
75
+ ## Authoritative context
76
+
77
+ When changing anything in the SDK, HiTL, or hashing paths:
78
+
79
+ - `docs/adr/ADR-001` — canonical hash spec (frozen)
80
+ - `docs/adr/ADR-002` — ingest failure isolation
81
+ - `docs/adr/ADR-006` — redaction contract
82
+ - `docs/adr/ADR-007` — HiTL checkpoint design
83
+ - `AGENTS_Phase1_Sprint4.md` — sprint plan with naming contract, six binding flags, ADR-007 summary, the launch review checklist. **Gitignored**, so absent from fresh clones; it's a working doc for whoever's driving the sprint.
84
+ - `rootsign_review.md` — pre-launch audit findings. Also gitignored. High-severity items were fixed in commit 128cec5; the remainder is the Pre-Phase-2 backlog (concurrency on approvals, payload→hash binding at verify, HiTL classification edge cases, CLI polish).
85
+
86
+ ## Conventions
87
+
88
+ - **Commits:** `type(scope): short description` (see CONTRIBUTING). Recent history matches: `fix(packaging):`, `fix(security):`, `feat(sdk):`, `docs:`. Body explains *why*, references file:line, and includes a `Co-Authored-By` trailer when relevant.
89
+ - **Branches:** `feat/`, `fix/`, `test/`, `docs/` prefixes.
90
+ - **Hard "no":** mock-based integration tests (real PG+TimescaleDB only), sync SQLAlchemy outside Alembic, changing `compute_action_self_hash` without a new ADR, silently swallowing ingest failures (must log at WARNING), committing/pushing project or sprint artifacts (see top section).
@@ -0,0 +1,82 @@
1
+ # Contributing to RootSign
2
+
3
+ ## Welcome
4
+
5
+ RootSign is the open-source agent capture layer of the Providex AI Agent Accountability Platform. We welcome contributions of all kinds: bug fixes, documentation improvements, new framework integrations, and test coverage.
6
+
7
+ ## Before you contribute
8
+
9
+ - **Code of Conduct.** RootSign adopts the [Contributor Covenant v2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/) as its code of conduct. By participating in this project (issues, PRs, discussions, Discord), you agree to uphold its standards. Report unacceptable behavior to `info@getprovidex.com`.
10
+ - Sign the [CLA](CLA.md) (automated — you'll be prompted on your first PR)
11
+ - Check the issue tracker for existing discussion before opening a new issue
12
+
13
+ ## Development setup
14
+
15
+ ```bash
16
+ git clone https://github.com/Providex-AI/rootsign
17
+ cd rootsign
18
+ pip install -e '.[dev]' # installs dev + test deps
19
+ docker-compose up -d db # PostgreSQL + TimescaleDB
20
+ rootsign-admin init # alembic upgrade head
21
+ python -m pytest tests/unit/ -v # unit tests (no DB needed at runtime — see note)
22
+ python -m pytest tests/integration/ -v # integration tests (needs DB)
23
+ ```
24
+
25
+ > **Python:** RootSign requires Python 3.11 or 3.12. We do not support 3.10 or below.
26
+ >
27
+ > The package's `requires-python` is `>=3.11,<3.15`, but the `[crewai]` extra currently lacks wheels for 3.13/3.14 so installs of `'.[crewai]'` on those versions fail with `No matching distribution found`. Bump the recommendation only after upstream ships matching wheels.
28
+ >
29
+ > **Always invoke pytest as `python -m pytest`.** If you `brew install`-ed pytest, the system binary will resolve ahead of the venv's pytest on PATH and run under the system Python — which does not see your venv's site-packages and will fail with confusing `ModuleNotFoundError` (typically on `sqlalchemy` first). `python -m pytest` always uses the venv's interpreter.
30
+ >
31
+ > **Note on unit tests:** The session-scoped `_bootstrap_test_db` fixture in `tests/conftest.py` runs alembic against the test DB before any test (including unit tests). Bring `docker-compose up -d db` up first.
32
+
33
+ ## Branch naming
34
+
35
+ ```
36
+ feat/[short-description] # new feature
37
+ fix/[short-description] # bug fix
38
+ test/[short-description] # test additions
39
+ docs/[short-description] # documentation only
40
+ ```
41
+
42
+ ## Commit message format
43
+
44
+ ```
45
+ type(scope): short description
46
+ ```
47
+
48
+ Examples:
49
+ ```
50
+ feat(sdk): add CrewAI tool wrapper
51
+ fix(hashing): correct canonical field order
52
+ test(crud): add verify_chain corruption test
53
+ docs(adr): add ADR-004 for retry strategy
54
+ ```
55
+
56
+ ## Pull request requirements
57
+
58
+ - All existing tests must pass: `pytest tests/ -v`
59
+ - New code must have test coverage >= 90%
60
+ - Overall coverage must not drop below 85% (enforced by `fail_under = 85` in `pyproject.toml`)
61
+ - No breaking changes to the canonical hash spec without a new ADR (see [ADR-001](docs/adr/ADR-001-hash-canonical-spec.md))
62
+ - Framework integrations must pass contract tests on all supported framework versions (see CI matrix)
63
+ - Run `ruff check .` and `ruff format .` before pushing
64
+
65
+ ## What we will NOT merge
66
+
67
+ - Changes to `compute_action_self_hash` canonical spec (see [ADR-001](docs/adr/ADR-001-hash-canonical-spec.md)) without a new ADR approved by the maintainer
68
+ - Synchronous SQLAlchemy in any non-Alembic code
69
+ - Mock-based integration tests (real PostgreSQL + TimescaleDB only — see [the data model rationale](AGENTS.md))
70
+ - Any PR that reduces test coverage below 85% overall
71
+ - Code that swallows ingest failures silently (RootSign's promise is that ingest never raises into the agent, but failures *must* be logged at WARNING level — see [ADR-002](docs/adr/ADR-002-transport-agnostic-client.md))
72
+
73
+ ## Adding a new framework integration
74
+
75
+ 1. Open a `framework_integration` issue first so we can discuss API surface and version targets
76
+ 2. Copy the LangGraph integration as a reference (lands in Sprint 2)
77
+ 3. Implement contract tests against a minimum of two framework versions (latest stable + previous minor) — see [ADR-003](docs/adr/ADR-003-framework-contract-tests.md)
78
+ 4. Update `docs/framework-support.md` (created in Sprint 2)
79
+
80
+ ## Questions?
81
+
82
+ Open a [GitHub Discussion](https://github.com/Providex-AI/rootsign/discussions). A `#rootsign` channel on the LangChain Discord is coming alongside Sprint 2.
@@ -0,0 +1,11 @@
1
+ # Contributors
2
+
3
+ Thank you to everyone who has contributed to RootSign.
4
+
5
+ ## Maintainers
6
+
7
+ - Olasile Abolade ([@oabolade](https://github.com/oabolade)) — Founder, Providex AI
8
+
9
+ ## Contributors
10
+
11
+ *Your name here (@your-github-handle) — one line description of what you worked on*