policynim 0.1.0__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 (144) hide show
  1. policynim-0.1.0/.dockerignore +14 -0
  2. policynim-0.1.0/.env.development.example +27 -0
  3. policynim-0.1.0/.env.example +36 -0
  4. policynim-0.1.0/.env.production.example +35 -0
  5. policynim-0.1.0/.github/workflows/ci.yml +54 -0
  6. policynim-0.1.0/.github/workflows/hosted-smoke.yml +42 -0
  7. policynim-0.1.0/.github/workflows/release.yml +291 -0
  8. policynim-0.1.0/.gitignore +19 -0
  9. policynim-0.1.0/.pre-commit-config.yaml +19 -0
  10. policynim-0.1.0/.python-version +2 -0
  11. policynim-0.1.0/.threadloop/config.json +4 -0
  12. policynim-0.1.0/Dockerfile +43 -0
  13. policynim-0.1.0/Dockerfile.railway +45 -0
  14. policynim-0.1.0/LICENSE +21 -0
  15. policynim-0.1.0/PKG-INFO +284 -0
  16. policynim-0.1.0/README.md +217 -0
  17. policynim-0.1.0/docs/ai-engineer-miami-context-plane.md +33 -0
  18. policynim-0.1.0/docs/architecture-diagram.md +282 -0
  19. policynim-0.1.0/docs/architecture.md +439 -0
  20. policynim-0.1.0/docs/assets/readme/policynim-beta-dark-landing-preview.png +0 -0
  21. policynim-0.1.0/docs/contributor-guide.md +225 -0
  22. policynim-0.1.0/docs/demo-script.md +265 -0
  23. policynim-0.1.0/docs/extreme-programming-with-agents.md +109 -0
  24. policynim-0.1.0/docs/hosted-beta-operations.md +304 -0
  25. policynim-0.1.0/docs/index.md +45 -0
  26. policynim-0.1.0/docs/limitations.md +138 -0
  27. policynim-0.1.0/docs/public-source-grounding.md +118 -0
  28. policynim-0.1.0/docs/release.md +84 -0
  29. policynim-0.1.0/docs/workflows.md +587 -0
  30. policynim-0.1.0/evals/default_cases.json +61 -0
  31. policynim-0.1.0/examples/claude-code/README.md +104 -0
  32. policynim-0.1.0/examples/codex/README.md +121 -0
  33. policynim-0.1.0/packaging/pyinstaller.spec +62 -0
  34. policynim-0.1.0/packmind.json +4 -0
  35. policynim-0.1.0/policies/TEMPLATE.md +52 -0
  36. policynim-0.1.0/policies/architecture/api-versioning-guidance.md +46 -0
  37. policynim-0.1.0/policies/architecture/background-job-design-rules.md +47 -0
  38. policynim-0.1.0/policies/backend/backend-logging-standard.md +48 -0
  39. policynim-0.1.0/policies/backend/config-validation-and-fail-closed.md +43 -0
  40. policynim-0.1.0/policies/backend/request-correlation-and-tracing-standard.md +45 -0
  41. policynim-0.1.0/policies/security/auth-sensitive-code-review-standard.md +47 -0
  42. policynim-0.1.0/policies/security/secrets-redaction-and-handling.md +46 -0
  43. policynim-0.1.0/policies/security/session-lifetime-and-token-boundaries.md +41 -0
  44. policynim-0.1.0/pyproject.toml +98 -0
  45. policynim-0.1.0/pyrightconfig.json +25 -0
  46. policynim-0.1.0/railway.toml +10 -0
  47. policynim-0.1.0/scripts/install.ps1 +156 -0
  48. policynim-0.1.0/scripts/install.sh +216 -0
  49. policynim-0.1.0/src/policynim/__init__.py +1 -0
  50. policynim-0.1.0/src/policynim/assets/beta/beta-page.js +58 -0
  51. policynim-0.1.0/src/policynim/assets/beta/beta-theme-init.js +16 -0
  52. policynim-0.1.0/src/policynim/assets/beta/beta.css +687 -0
  53. policynim-0.1.0/src/policynim/assets/beta/policynim_darkmode.jpg +0 -0
  54. policynim-0.1.0/src/policynim/assets/beta/policynim_lightmode.png +0 -0
  55. policynim-0.1.0/src/policynim/config_discovery.py +309 -0
  56. policynim-0.1.0/src/policynim/contracts.py +157 -0
  57. policynim-0.1.0/src/policynim/errors.py +43 -0
  58. policynim-0.1.0/src/policynim/ingest/__init__.py +24 -0
  59. policynim-0.1.0/src/policynim/ingest/chunking.py +307 -0
  60. policynim-0.1.0/src/policynim/ingest/loader.py +113 -0
  61. policynim-0.1.0/src/policynim/ingest/parser.py +940 -0
  62. policynim-0.1.0/src/policynim/interfaces/__init__.py +1 -0
  63. policynim-0.1.0/src/policynim/interfaces/cli.py +1009 -0
  64. policynim-0.1.0/src/policynim/interfaces/mcp.py +1034 -0
  65. policynim-0.1.0/src/policynim/providers/__init__.py +25 -0
  66. policynim-0.1.0/src/policynim/providers/nvidia.py +1135 -0
  67. policynim-0.1.0/src/policynim/providers/nvidia_eval.py +141 -0
  68. policynim-0.1.0/src/policynim/providers/nvidia_guardrails.py +383 -0
  69. policynim-0.1.0/src/policynim/runtime_paths.py +163 -0
  70. policynim-0.1.0/src/policynim/services/__init__.py +71 -0
  71. policynim-0.1.0/src/policynim/services/beta_auth.py +351 -0
  72. policynim-0.1.0/src/policynim/services/compiler.py +264 -0
  73. policynim-0.1.0/src/policynim/services/conformance.py +323 -0
  74. policynim-0.1.0/src/policynim/services/dump.py +31 -0
  75. policynim-0.1.0/src/policynim/services/eval.py +1763 -0
  76. policynim-0.1.0/src/policynim/services/evidence_trace.py +353 -0
  77. policynim-0.1.0/src/policynim/services/health.py +202 -0
  78. policynim-0.1.0/src/policynim/services/ingest.py +217 -0
  79. policynim-0.1.0/src/policynim/services/preflight.py +406 -0
  80. policynim-0.1.0/src/policynim/services/regeneration.py +653 -0
  81. policynim-0.1.0/src/policynim/services/router.py +362 -0
  82. policynim-0.1.0/src/policynim/services/runtime_decision.py +428 -0
  83. policynim-0.1.0/src/policynim/services/runtime_evidence_report.py +156 -0
  84. policynim-0.1.0/src/policynim/services/runtime_execution.py +575 -0
  85. policynim-0.1.0/src/policynim/services/search.py +110 -0
  86. policynim-0.1.0/src/policynim/settings.py +383 -0
  87. policynim-0.1.0/src/policynim/storage/__init__.py +7 -0
  88. policynim-0.1.0/src/policynim/storage/auth_store.py +628 -0
  89. policynim-0.1.0/src/policynim/storage/lancedb.py +188 -0
  90. policynim-0.1.0/src/policynim/storage/runtime_evidence.py +211 -0
  91. policynim-0.1.0/src/policynim/templates/beta/dashboard.html.j2 +130 -0
  92. policynim-0.1.0/src/policynim/templates/beta/landing.html.j2 +85 -0
  93. policynim-0.1.0/src/policynim/templates/beta/page.html.j2 +17 -0
  94. policynim-0.1.0/src/policynim/templates/beta/partials/command_card.html.j2 +19 -0
  95. policynim-0.1.0/src/policynim/templates/beta/partials/logo.html.j2 +18 -0
  96. policynim-0.1.0/src/policynim/templates/beta/partials/new_key_panel.html.j2 +24 -0
  97. policynim-0.1.0/src/policynim/templates/beta/partials/notice.html.j2 +4 -0
  98. policynim-0.1.0/src/policynim/templates/beta/partials/theme_toggle.html.j2 +10 -0
  99. policynim-0.1.0/src/policynim/templates/nvidia_guardrails/preflight_output/config.yml +31 -0
  100. policynim-0.1.0/src/policynim/templates/nvidia_guardrails/preflight_output/rails.co +2 -0
  101. policynim-0.1.0/src/policynim/types.py +1114 -0
  102. policynim-0.1.0/tests/README.md +88 -0
  103. policynim-0.1.0/tests/test_auth_store.py +232 -0
  104. policynim-0.1.0/tests/test_beta_auth.py +149 -0
  105. policynim-0.1.0/tests/test_beta_portal.py +340 -0
  106. policynim-0.1.0/tests/test_ci_workflows.py +113 -0
  107. policynim-0.1.0/tests/test_cli.py +2665 -0
  108. policynim-0.1.0/tests/test_compiler_service.py +303 -0
  109. policynim-0.1.0/tests/test_docker_build_live.py +149 -0
  110. policynim-0.1.0/tests/test_dockerfile_contract.py +58 -0
  111. policynim-0.1.0/tests/test_docs_hosted_onboarding.py +140 -0
  112. policynim-0.1.0/tests/test_docs_runtime_workflows.py +171 -0
  113. policynim-0.1.0/tests/test_eval_service.py +515 -0
  114. policynim-0.1.0/tests/test_health_service.py +387 -0
  115. policynim-0.1.0/tests/test_hosted_mcp_live.py +130 -0
  116. policynim-0.1.0/tests/test_ingest.py +431 -0
  117. policynim-0.1.0/tests/test_ingest_service.py +280 -0
  118. policynim-0.1.0/tests/test_installer_contract.py +234 -0
  119. policynim-0.1.0/tests/test_lancedb.py +68 -0
  120. policynim-0.1.0/tests/test_mcp.py +1030 -0
  121. policynim-0.1.0/tests/test_nemo_agent_toolkit_policy_conformance.py +112 -0
  122. policynim-0.1.0/tests/test_nemo_evaluator_policy_conformance.py +110 -0
  123. policynim-0.1.0/tests/test_nemo_guardrails_preflight_generator.py +388 -0
  124. policynim-0.1.0/tests/test_nvidia_embedder.py +114 -0
  125. policynim-0.1.0/tests/test_nvidia_generator.py +240 -0
  126. policynim-0.1.0/tests/test_nvidia_live.py +96 -0
  127. policynim-0.1.0/tests/test_nvidia_policy_compiler.py +324 -0
  128. policynim-0.1.0/tests/test_nvidia_policy_conformance.py +280 -0
  129. policynim-0.1.0/tests/test_nvidia_reranker.py +274 -0
  130. policynim-0.1.0/tests/test_package_release.py +45 -0
  131. policynim-0.1.0/tests/test_policy_conformance_service.py +272 -0
  132. policynim-0.1.0/tests/test_policy_evidence_trace_service.py +285 -0
  133. policynim-0.1.0/tests/test_policy_regeneration_service.py +542 -0
  134. policynim-0.1.0/tests/test_preflight_service.py +756 -0
  135. policynim-0.1.0/tests/test_router_service.py +294 -0
  136. policynim-0.1.0/tests/test_runtime_decision_service.py +595 -0
  137. policynim-0.1.0/tests/test_runtime_evidence_report_service.py +449 -0
  138. policynim-0.1.0/tests/test_runtime_evidence_store.py +272 -0
  139. policynim-0.1.0/tests/test_runtime_execution_service.py +560 -0
  140. policynim-0.1.0/tests/test_runtime_paths.py +281 -0
  141. policynim-0.1.0/tests/test_search_service.py +264 -0
  142. policynim-0.1.0/tests/test_service_factories.py +308 -0
  143. policynim-0.1.0/tests/test_settings_and_types.py +917 -0
  144. policynim-0.1.0/uv.lock +4459 -0
@@ -0,0 +1,14 @@
1
+ .env
2
+ .git
3
+ .github
4
+ .plan
5
+ .pytest_cache
6
+ .ruff_cache
7
+ .venv
8
+ .benchmarks
9
+ .qodo
10
+ .threadloop
11
+ .voice
12
+ __pycache__/
13
+ data/
14
+ dist/
@@ -0,0 +1,27 @@
1
+ # Local development defaults.
2
+ # Copy this file to .env for local CLI, eval, and stdio MCP work.
3
+ NVIDIA_API_KEY=
4
+ POLICYNIM_ENV=development
5
+ POLICYNIM_LANCEDB_URI=data/lancedb
6
+ POLICYNIM_LANCEDB_TABLE=policy_chunks
7
+ POLICYNIM_RUNTIME_RULES_ARTIFACT_PATH=data/runtime/runtime_rules.json
8
+ POLICYNIM_RUNTIME_EVIDENCE_DB_PATH=data/runtime/runtime_evidence.sqlite3
9
+ POLICYNIM_RUNTIME_SHELL_TIMEOUT_SECONDS=300
10
+ POLICYNIM_EVAL_WORKSPACE_DIR=data/evals/workspace
11
+ POLICYNIM_DEFAULT_TOP_K=5
12
+ POLICYNIM_EMBED_BATCH_SIZE=32
13
+ POLICYNIM_NVIDIA_CHAT_MODEL=nvidia/llama-3.3-nemotron-super-49b-v1.5
14
+ POLICYNIM_NVIDIA_EMBED_MODEL=nvidia/llama-nemotron-embed-1b-v2
15
+ POLICYNIM_NVIDIA_RERANK_MODEL=nvidia/llama-nemotron-rerank-1b-v2
16
+ POLICYNIM_NVIDIA_BASE_URL=https://integrate.api.nvidia.com/v1
17
+ POLICYNIM_NVIDIA_RETRIEVAL_BASE_URL=https://ai.api.nvidia.com/v1/retrieval
18
+ POLICYNIM_NVIDIA_TIMEOUT_SECONDS=30
19
+ POLICYNIM_NVIDIA_MAX_RETRIES=2
20
+ POLICYNIM_MCP_HOST=127.0.0.1
21
+ POLICYNIM_MCP_PORT=6000
22
+ POLICYNIM_MCP_REQUIRE_AUTH=false
23
+ POLICYNIM_EVAL_UI_PORT=8001
24
+
25
+ # Optional hosted-only settings:
26
+ # POLICYNIM_MCP_BEARER_TOKENS=token-a,token-b
27
+ # POLICYNIM_MCP_PUBLIC_BASE_URL=https://your-host
@@ -0,0 +1,36 @@
1
+ # Backward-compatible local-development example.
2
+ # Prefer copying .env.development.example for local work and
3
+ # .env.production.example when preparing hosted Railway variables.
4
+ NVIDIA_API_KEY=
5
+ POLICYNIM_ENV=development
6
+ POLICYNIM_LANCEDB_URI=data/lancedb
7
+ POLICYNIM_LANCEDB_TABLE=policy_chunks
8
+ POLICYNIM_RUNTIME_RULES_ARTIFACT_PATH=data/runtime/runtime_rules.json
9
+ POLICYNIM_RUNTIME_EVIDENCE_DB_PATH=data/runtime/runtime_evidence.sqlite3
10
+ POLICYNIM_RUNTIME_SHELL_TIMEOUT_SECONDS=300
11
+ POLICYNIM_EVAL_WORKSPACE_DIR=data/evals/workspace
12
+ POLICYNIM_DEFAULT_TOP_K=5
13
+ POLICYNIM_EMBED_BATCH_SIZE=32
14
+ POLICYNIM_NVIDIA_CHAT_MODEL=nvidia/llama-3.3-nemotron-super-49b-v1.5
15
+ POLICYNIM_NVIDIA_EMBED_MODEL=nvidia/llama-nemotron-embed-1b-v2
16
+ POLICYNIM_NVIDIA_RERANK_MODEL=nvidia/llama-nemotron-rerank-1b-v2
17
+ POLICYNIM_NVIDIA_BASE_URL=https://integrate.api.nvidia.com/v1
18
+ POLICYNIM_NVIDIA_RETRIEVAL_BASE_URL=https://ai.api.nvidia.com/v1/retrieval
19
+ POLICYNIM_NVIDIA_TIMEOUT_SECONDS=30
20
+ POLICYNIM_NVIDIA_MAX_RETRIES=2
21
+ POLICYNIM_MCP_HOST=127.0.0.1
22
+ POLICYNIM_MCP_PORT=6000
23
+ POLICYNIM_MCP_REQUIRE_AUTH=false
24
+ POLICYNIM_EVAL_UI_PORT=8001
25
+
26
+ # Optional hosted-only settings:
27
+ # POLICYNIM_MCP_BEARER_TOKENS=token-a,token-b
28
+ # POLICYNIM_MCP_PUBLIC_BASE_URL=https://your-host
29
+ # POLICYNIM_BETA_SIGNUP_ENABLED=true
30
+ # POLICYNIM_BETA_AUTH_DB_PATH=data/runtime/auth.sqlite3
31
+ # POLICYNIM_BETA_SESSION_SECRET=replace-with-a-random-secret
32
+ # POLICYNIM_BETA_GITHUB_CLIENT_ID=github-oauth-client-id
33
+ # POLICYNIM_BETA_GITHUB_CLIENT_SECRET=github-oauth-client-secret
34
+ # POLICYNIM_BETA_DAILY_REQUEST_QUOTA=500
35
+ # POLICYNIM_BETA_AUTH_RATE_LIMIT_MAX_ATTEMPTS=20
36
+ # POLICYNIM_BETA_AUTH_RATE_LIMIT_WINDOW_SECONDS=900
@@ -0,0 +1,35 @@
1
+ # Hosted production defaults for Docker and Railway.
2
+ # Railway injects PORT. Leave POLICYNIM_MCP_PORT unset unless you need an override.
3
+ # Required at Docker build time for baked ingest and at runtime for live hosted retrieval.
4
+ NVIDIA_API_KEY=
5
+ POLICYNIM_ENV=production
6
+ POLICYNIM_LANCEDB_URI=/app/data/lancedb-baked
7
+ POLICYNIM_LANCEDB_TABLE=policy_chunks
8
+ # Keep the compiled rules artifact with the baked/runtime data layout.
9
+ POLICYNIM_RUNTIME_RULES_ARTIFACT_PATH=/app/data/runtime/runtime_rules.json
10
+ # Keep mutable runtime evidence on the writable state volume.
11
+ POLICYNIM_RUNTIME_EVIDENCE_DB_PATH=/app/state/runtime_evidence.sqlite3
12
+ POLICYNIM_RUNTIME_SHELL_TIMEOUT_SECONDS=300
13
+ POLICYNIM_DEFAULT_TOP_K=5
14
+ POLICYNIM_EMBED_BATCH_SIZE=32
15
+ POLICYNIM_NVIDIA_CHAT_MODEL=nvidia/llama-3.3-nemotron-super-49b-v1.5
16
+ POLICYNIM_NVIDIA_EMBED_MODEL=nvidia/llama-nemotron-embed-1b-v2
17
+ POLICYNIM_NVIDIA_RERANK_MODEL=nvidia/llama-nemotron-rerank-1b-v2
18
+ POLICYNIM_NVIDIA_BASE_URL=https://integrate.api.nvidia.com/v1
19
+ POLICYNIM_NVIDIA_RETRIEVAL_BASE_URL=https://ai.api.nvidia.com/v1/retrieval
20
+ POLICYNIM_NVIDIA_TIMEOUT_SECONDS=30
21
+ POLICYNIM_NVIDIA_MAX_RETRIES=2
22
+ POLICYNIM_MCP_HOST=0.0.0.0
23
+ POLICYNIM_MCP_REQUIRE_AUTH=false
24
+ POLICYNIM_BETA_SIGNUP_ENABLED=false
25
+ POLICYNIM_BETA_AUTH_DB_PATH=/app/state/auth.sqlite3
26
+ POLICYNIM_BETA_DAILY_REQUEST_QUOTA=500
27
+ POLICYNIM_BETA_AUTH_RATE_LIMIT_MAX_ATTEMPTS=20
28
+ POLICYNIM_BETA_AUTH_RATE_LIMIT_WINDOW_SECONDS=900
29
+
30
+ # Optional hosted auth after you generate a public domain:
31
+ # POLICYNIM_MCP_BEARER_TOKENS=token-a,token-b
32
+ # POLICYNIM_MCP_PUBLIC_BASE_URL=https://your-host
33
+ # POLICYNIM_BETA_SESSION_SECRET=replace-with-a-random-secret
34
+ # POLICYNIM_BETA_GITHUB_CLIENT_ID=github-oauth-client-id
35
+ # POLICYNIM_BETA_GITHUB_CLIENT_SECRET=github-oauth-client-secret
@@ -0,0 +1,54 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - main
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ lint:
14
+ runs-on: ubuntu-24.04
15
+ steps:
16
+ - name: Check out repository
17
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
18
+
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@d0d8abe699bfb85fec6de9f7adb5ae17292296ff # v6
21
+
22
+ - name: Set up Python 3.11
23
+ uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
24
+ with:
25
+ python-version: "3.11"
26
+
27
+ - name: Sync dependencies
28
+ run: uv sync --group test --group dev
29
+
30
+ - name: Run Ruff
31
+ run: uv run ruff check
32
+
33
+ - name: Run Pyright
34
+ run: uv run pyright
35
+
36
+ test:
37
+ runs-on: ubuntu-24.04
38
+ steps:
39
+ - name: Check out repository
40
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
41
+
42
+ - name: Install uv
43
+ uses: astral-sh/setup-uv@d0d8abe699bfb85fec6de9f7adb5ae17292296ff # v6
44
+
45
+ - name: Set up Python 3.11
46
+ uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
47
+ with:
48
+ python-version: "3.11"
49
+
50
+ - name: Sync dependencies
51
+ run: uv sync --group test --group dev
52
+
53
+ - name: Run offline pytest
54
+ run: uv run pytest -q -m "not live and not docker_live"
@@ -0,0 +1,42 @@
1
+ name: Hosted Beta Smoke
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ permissions:
7
+ contents: read
8
+
9
+ jobs:
10
+ hosted-smoke:
11
+ runs-on: ubuntu-24.04
12
+ env:
13
+ POLICYNIM_BETA_MCP_URL: ${{ secrets.POLICYNIM_BETA_MCP_URL }}
14
+ POLICYNIM_BETA_MCP_TOKEN: ${{ secrets.POLICYNIM_BETA_MCP_TOKEN }}
15
+ steps:
16
+ - name: Check out repository
17
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
18
+
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@d0d8abe699bfb85fec6de9f7adb5ae17292296ff # v6
21
+
22
+ - name: Set up Python 3.11
23
+ uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
24
+ with:
25
+ python-version: "3.11"
26
+
27
+ - name: Validate hosted smoke secrets
28
+ run: |
29
+ test -n "$POLICYNIM_BETA_MCP_URL" || {
30
+ echo "POLICYNIM_BETA_MCP_URL secret is required for hosted smoke tests."
31
+ exit 1
32
+ }
33
+ test -n "$POLICYNIM_BETA_MCP_TOKEN" || {
34
+ echo "POLICYNIM_BETA_MCP_TOKEN secret is required for hosted smoke tests."
35
+ exit 1
36
+ }
37
+
38
+ - name: Sync dependencies
39
+ run: uv sync --group test --group dev
40
+
41
+ - name: Run hosted live smoke
42
+ run: uv run --group test pytest -q -m live tests/test_hosted_mcp_live.py
@@ -0,0 +1,291 @@
1
+ name: Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ version:
7
+ description: "Release version or tag, for example 0.1.0 or v0.1.0."
8
+ required: false
9
+ type: string
10
+ publish_pypi:
11
+ description: "Publish the built Python distribution to PyPI using trusted publishing."
12
+ required: false
13
+ default: false
14
+ type: boolean
15
+ push:
16
+ tags:
17
+ - "v*.*.*"
18
+
19
+ permissions:
20
+ contents: read
21
+
22
+ env:
23
+ PYTHON_VERSION: "3.11"
24
+
25
+ jobs:
26
+ verify:
27
+ runs-on: ubuntu-24.04
28
+ steps:
29
+ - name: Check out repository
30
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
31
+
32
+ - name: Install uv
33
+ uses: astral-sh/setup-uv@d0d8abe699bfb85fec6de9f7adb5ae17292296ff # v6
34
+
35
+ - name: Set up Python
36
+ uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
37
+ with:
38
+ python-version: ${{ env.PYTHON_VERSION }}
39
+
40
+ - name: Sync dependencies
41
+ run: uv sync --group test --group dev
42
+
43
+ - name: Check lockfile
44
+ run: uv lock --check
45
+
46
+ - name: Run Ruff
47
+ run: uv run ruff check .
48
+
49
+ - name: Run Pyright
50
+ run: uv run pyright
51
+
52
+ - name: Run offline pytest
53
+ run: uv run pytest -q -m "not live and not docker_live"
54
+
55
+ - name: Build Python distribution
56
+ run: uv build --out-dir dist
57
+
58
+ - name: Upload Python distribution
59
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
60
+ with:
61
+ name: python-dist
62
+ path: dist/*
63
+ if-no-files-found: error
64
+
65
+ wheel-smoke:
66
+ runs-on: ubuntu-24.04
67
+ needs: verify
68
+ steps:
69
+ - name: Download Python distribution
70
+ uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
71
+ with:
72
+ name: python-dist
73
+ path: dist
74
+
75
+ - name: Set up Python
76
+ uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
77
+ with:
78
+ python-version: ${{ env.PYTHON_VERSION }}
79
+
80
+ - name: Smoke install built wheel
81
+ run: |
82
+ python -m venv /tmp/policynim-wheel-smoke
83
+ /tmp/policynim-wheel-smoke/bin/python -m pip install dist/*.whl
84
+ /tmp/policynim-wheel-smoke/bin/policynim --help
85
+ /tmp/policynim-wheel-smoke/bin/policynim --version
86
+
87
+ standalone-build:
88
+ needs: verify
89
+ strategy:
90
+ fail-fast: false
91
+ matrix:
92
+ include:
93
+ - os: ubuntu-24.04
94
+ platform: linux-amd64
95
+ archive: tar
96
+ - os: macos-13
97
+ platform: darwin-amd64
98
+ archive: tar
99
+ - os: macos-14
100
+ platform: darwin-arm64
101
+ archive: tar
102
+ - os: windows-2022
103
+ platform: windows-amd64
104
+ archive: zip
105
+ runs-on: ${{ matrix.os }}
106
+ steps:
107
+ - name: Check out repository
108
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
109
+
110
+ - name: Install uv
111
+ uses: astral-sh/setup-uv@d0d8abe699bfb85fec6de9f7adb5ae17292296ff # v6
112
+
113
+ - name: Set up Python
114
+ uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
115
+ with:
116
+ python-version: ${{ env.PYTHON_VERSION }}
117
+
118
+ - name: Resolve release tag
119
+ env:
120
+ REQUESTED_VERSION: ${{ inputs.version }}
121
+ shell: bash
122
+ run: |
123
+ python - <<'PY' >> "$GITHUB_ENV"
124
+ import os
125
+ import tomllib
126
+ from pathlib import Path
127
+
128
+ project = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))
129
+ project_version = project["project"]["version"]
130
+ if os.environ.get("GITHUB_REF_TYPE") == "tag":
131
+ tag = os.environ["GITHUB_REF_NAME"]
132
+ requested_version = tag.removeprefix("v")
133
+ else:
134
+ requested = os.environ.get("REQUESTED_VERSION", "").strip()
135
+ if requested:
136
+ requested_version = requested.removeprefix("v")
137
+ tag = f"v{requested_version}"
138
+ else:
139
+ requested_version = project_version
140
+ tag = f"v{project_version}"
141
+ if requested_version != project_version:
142
+ raise SystemExit(
143
+ "Release version mismatch: "
144
+ f"requested {requested_version}, pyproject.toml has {project_version}."
145
+ )
146
+ print(f"RELEASE_TAG={tag}")
147
+ PY
148
+
149
+ - name: Sync release dependencies
150
+ run: uv sync --group release
151
+
152
+ - name: Build standalone bundle
153
+ run: uv run --group release pyinstaller --clean --noconfirm packaging/pyinstaller.spec
154
+
155
+ - name: Smoke standalone bundle
156
+ shell: bash
157
+ run: |
158
+ if [ "${{ matrix.platform }}" = "windows-amd64" ]; then
159
+ dist/policynim/policynim.exe --help
160
+ dist/policynim/policynim.exe --version
161
+ else
162
+ dist/policynim/policynim --help
163
+ dist/policynim/policynim --version
164
+ fi
165
+
166
+ - name: Archive Unix standalone bundle
167
+ if: matrix.archive == 'tar'
168
+ shell: bash
169
+ run: |
170
+ mkdir -p artifacts
171
+ case "${{ matrix.platform }}" in
172
+ linux-amd64) ASSET_NAME="policynim-${RELEASE_TAG}-linux-amd64.tar.gz" ;;
173
+ darwin-amd64) ASSET_NAME="policynim-${RELEASE_TAG}-darwin-amd64.tar.gz" ;;
174
+ darwin-arm64) ASSET_NAME="policynim-${RELEASE_TAG}-darwin-arm64.tar.gz" ;;
175
+ *) echo "Unsupported release platform: ${{ matrix.platform }}" >&2; exit 1 ;;
176
+ esac
177
+ tar -C dist -czf "artifacts/${ASSET_NAME}" policynim
178
+
179
+ - name: Archive Windows standalone bundle
180
+ if: matrix.archive == 'zip'
181
+ shell: pwsh
182
+ run: |
183
+ New-Item -ItemType Directory -Force -Path artifacts | Out-Null
184
+ $RELEASE_TAG = $env:RELEASE_TAG
185
+ $AssetName = "policynim-${RELEASE_TAG}-windows-amd64.zip"
186
+ Compress-Archive -Path "dist/policynim/*" -DestinationPath "artifacts/$AssetName" -Force
187
+
188
+ - name: Upload standalone bundle
189
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
190
+ with:
191
+ name: standalone-${{ matrix.platform }}
192
+ path: artifacts/*
193
+ if-no-files-found: error
194
+
195
+ publish-github-release:
196
+ runs-on: ubuntu-24.04
197
+ needs:
198
+ - verify
199
+ - wheel-smoke
200
+ - standalone-build
201
+ permissions:
202
+ contents: write
203
+ steps:
204
+ - name: Check out repository
205
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
206
+
207
+ - name: Download release artifacts
208
+ uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
209
+ with:
210
+ path: release-downloads
211
+
212
+ - name: Resolve release tag
213
+ env:
214
+ REQUESTED_VERSION: ${{ inputs.version }}
215
+ run: |
216
+ python - <<'PY' >> "$GITHUB_ENV"
217
+ import os
218
+ import tomllib
219
+ from pathlib import Path
220
+
221
+ project = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))
222
+ project_version = project["project"]["version"]
223
+ if os.environ.get("GITHUB_REF_TYPE") == "tag":
224
+ tag = os.environ["GITHUB_REF_NAME"]
225
+ requested_version = tag.removeprefix("v")
226
+ else:
227
+ requested = os.environ.get("REQUESTED_VERSION", "").strip()
228
+ if requested:
229
+ requested_version = requested.removeprefix("v")
230
+ tag = f"v{requested_version}"
231
+ else:
232
+ requested_version = project_version
233
+ tag = f"v{project_version}"
234
+ if requested_version != project_version:
235
+ raise SystemExit(
236
+ "Release version mismatch: "
237
+ f"requested {requested_version}, pyproject.toml has {project_version}."
238
+ )
239
+ print(f"RELEASE_TAG={tag}")
240
+ PY
241
+
242
+ - name: Prepare release assets
243
+ run: |
244
+ mkdir -p release-assets
245
+ find release-downloads -type f -exec cp {} release-assets/ \;
246
+ cp scripts/install.sh release-assets/install.sh
247
+ cp scripts/install.ps1 release-assets/install.ps1
248
+ (
249
+ cd release-assets
250
+ sha256sum * > SHA256SUMS
251
+ )
252
+ cat > release-notes.md <<'EOF'
253
+ PolicyNIM release artifacts:
254
+
255
+ - Python wheel and source distribution for `pipx install policynim`
256
+ - Standalone CLI bundles for Linux, macOS, and Windows
257
+ - Unix and PowerShell installer scripts
258
+ - SHA256SUMS for release asset verification
259
+ EOF
260
+
261
+ - name: Create draft GitHub release
262
+ env:
263
+ GH_TOKEN: ${{ github.token }}
264
+ run: |
265
+ gh release create "$RELEASE_TAG" \
266
+ --draft \
267
+ --target "$GITHUB_SHA" \
268
+ --title "$RELEASE_TAG" \
269
+ --notes-file release-notes.md \
270
+ release-assets/*
271
+
272
+ publish-pypi:
273
+ runs-on: ubuntu-24.04
274
+ needs:
275
+ - verify
276
+ - wheel-smoke
277
+ if: startsWith(github.ref, 'refs/tags/v') || (github.event_name == 'workflow_dispatch' && inputs.publish_pypi)
278
+ environment: pypi
279
+ permissions:
280
+ id-token: write
281
+ contents: read
282
+ steps:
283
+ - name: Download Python distribution
284
+ uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
285
+ with:
286
+ name: python-dist
287
+ path: dist
288
+
289
+ - name: Publish to PyPI
290
+ # This Docker-based action publishes GHCR images under release tags, not commit SHA tags.
291
+ uses: pypa/gh-action-pypi-publish@v1.14.0 # 6733eb7d741f0b11ec6a39b58540dab7590f9b7d
@@ -0,0 +1,19 @@
1
+ .DS_Store
2
+ .plan/
3
+ .env
4
+ .env.*
5
+ !.env.example
6
+ !.env.development.example
7
+ !.env.production.example
8
+ .mypy_cache/
9
+ .pytest_cache/
10
+ .ruff_cache/
11
+ .venv/
12
+ .vscode/
13
+ .voice/
14
+ __pycache__/
15
+ build/
16
+ data/
17
+ dist/
18
+ *.pyc
19
+ .threadloop/state/
@@ -0,0 +1,19 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ - id: ruff-check
5
+ name: ruff check
6
+ entry: uv run --group dev ruff check --fix
7
+ language: system
8
+ types: [python]
9
+ - id: ruff-format
10
+ name: ruff format
11
+ entry: uv run --group dev ruff format
12
+ language: system
13
+ types: [python]
14
+ - id: pyright
15
+ name: pyright
16
+ entry: uv run --group dev pyright
17
+ language: system
18
+ pass_filenames: false
19
+ types: [python]
@@ -0,0 +1,2 @@
1
+ 3.11
2
+
@@ -0,0 +1,4 @@
1
+ {
2
+ "version": 1,
3
+ "createdAt": "2026-03-23T20:37:09.201Z"
4
+ }
@@ -0,0 +1,43 @@
1
+ # syntax=docker/dockerfile:1.7
2
+ ARG PYTHON_BASE_IMAGE=python:3.11.15-slim-trixie@sha256:9358444059ed78e2975ada2c189f1c1a3144a5dab6f35bff8c981afb38946634
3
+
4
+ FROM ${PYTHON_BASE_IMAGE} AS builder
5
+
6
+ ENV PYTHONDONTWRITEBYTECODE=1 \
7
+ PYTHONUNBUFFERED=1 \
8
+ POLICYNIM_LANCEDB_URI=/app/data/lancedb-baked
9
+
10
+ WORKDIR /app
11
+
12
+ RUN pip install --no-cache-dir uv==0.7.12
13
+
14
+ COPY pyproject.toml uv.lock README.md LICENSE ./
15
+ COPY src ./src
16
+ COPY policies ./policies
17
+ COPY evals ./evals
18
+
19
+ RUN uv sync --frozen
20
+ RUN --mount=type=secret,id=nvidia_api_key,required=true \
21
+ sh -c 'NVIDIA_API_KEY="$(cat /run/secrets/nvidia_api_key)" uv run policynim ingest'
22
+
23
+
24
+ FROM ${PYTHON_BASE_IMAGE} AS runtime
25
+
26
+ ENV PYTHONDONTWRITEBYTECODE=1 \
27
+ PYTHONUNBUFFERED=1 \
28
+ POLICYNIM_LANCEDB_URI=/app/data/lancedb-baked \
29
+ POLICYNIM_MCP_HOST=0.0.0.0 \
30
+ PATH=/app/.venv/bin:$PATH
31
+
32
+ WORKDIR /app
33
+
34
+ COPY --from=builder /app/.venv /app/.venv
35
+ COPY --from=builder /app/src /app/src
36
+ COPY --from=builder /app/policies /app/policies
37
+ COPY --from=builder /app/evals /app/evals
38
+ COPY --from=builder /app/pyproject.toml /app/pyproject.toml
39
+ COPY --from=builder /app/README.md /app/README.md
40
+ COPY --from=builder /app/LICENSE /app/LICENSE
41
+ COPY --from=builder /app/data/lancedb-baked /app/data/lancedb-baked
42
+
43
+ CMD ["policynim", "mcp", "--transport", "streamable-http"]
@@ -0,0 +1,45 @@
1
+ ARG PYTHON_BASE_IMAGE=python:3.11.15-slim-trixie@sha256:9358444059ed78e2975ada2c189f1c1a3144a5dab6f35bff8c981afb38946634
2
+
3
+ FROM ${PYTHON_BASE_IMAGE} AS builder
4
+
5
+ ENV PYTHONDONTWRITEBYTECODE=1 \
6
+ PYTHONUNBUFFERED=1 \
7
+ POLICYNIM_LANCEDB_URI=/app/data/lancedb-baked
8
+
9
+ WORKDIR /app
10
+
11
+ RUN pip install --no-cache-dir uv==0.7.12
12
+
13
+ COPY pyproject.toml uv.lock README.md LICENSE ./
14
+ COPY src ./src
15
+ COPY policies ./policies
16
+ COPY evals ./evals
17
+
18
+ # Railway's Dockerfile builder rejects non-cache mounts, so its deploy-specific
19
+ # Dockerfile still has to source the bake-time key from a build arg.
20
+ ARG NVIDIA_API_KEY
21
+
22
+ RUN uv sync --frozen
23
+ RUN NVIDIA_API_KEY="${NVIDIA_API_KEY}" uv run policynim ingest
24
+
25
+
26
+ FROM ${PYTHON_BASE_IMAGE} AS runtime
27
+
28
+ ENV PYTHONDONTWRITEBYTECODE=1 \
29
+ PYTHONUNBUFFERED=1 \
30
+ POLICYNIM_LANCEDB_URI=/app/data/lancedb-baked \
31
+ POLICYNIM_MCP_HOST=0.0.0.0 \
32
+ PATH=/app/.venv/bin:$PATH
33
+
34
+ WORKDIR /app
35
+
36
+ COPY --from=builder /app/.venv /app/.venv
37
+ COPY --from=builder /app/src /app/src
38
+ COPY --from=builder /app/policies /app/policies
39
+ COPY --from=builder /app/evals /app/evals
40
+ COPY --from=builder /app/pyproject.toml /app/pyproject.toml
41
+ COPY --from=builder /app/README.md /app/README.md
42
+ COPY --from=builder /app/LICENSE /app/LICENSE
43
+ COPY --from=builder /app/data/lancedb-baked /app/data/lancedb-baked
44
+
45
+ CMD ["policynim", "mcp", "--transport", "streamable-http"]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nnenna Ndukwe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.