dexpot 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 (39) hide show
  1. dexpot-0.1.0/.github/dependabot.yml +39 -0
  2. dexpot-0.1.0/.github/labeler.yml +33 -0
  3. dexpot-0.1.0/.github/workflows/changelog.yml +41 -0
  4. dexpot-0.1.0/.github/workflows/ci.yml +125 -0
  5. dexpot-0.1.0/.github/workflows/labeler.yml +26 -0
  6. dexpot-0.1.0/.github/workflows/release.yml +182 -0
  7. dexpot-0.1.0/.github/workflows/stale.yml +40 -0
  8. dexpot-0.1.0/.gitignore +15 -0
  9. dexpot-0.1.0/.pre-commit-config.yaml +14 -0
  10. dexpot-0.1.0/CHANGELOG.md +22 -0
  11. dexpot-0.1.0/CONTRIBUTING.md +95 -0
  12. dexpot-0.1.0/LICENSE +21 -0
  13. dexpot-0.1.0/Makefile +34 -0
  14. dexpot-0.1.0/PKG-INFO +378 -0
  15. dexpot-0.1.0/README.md +337 -0
  16. dexpot-0.1.0/ROADMAP.md +148 -0
  17. dexpot-0.1.0/changelog.d/README.md +21 -0
  18. dexpot-0.1.0/docs/releasing.md +79 -0
  19. dexpot-0.1.0/docs/reviewing.md +107 -0
  20. dexpot-0.1.0/examples/minimal.py +22 -0
  21. dexpot-0.1.0/pyproject.toml +122 -0
  22. dexpot-0.1.0/src/dexpot/__init__.py +13 -0
  23. dexpot-0.1.0/src/dexpot/app.py +693 -0
  24. dexpot-0.1.0/src/dexpot/cli.py +95 -0
  25. dexpot-0.1.0/src/dexpot/commands/__init__.py +1 -0
  26. dexpot-0.1.0/src/dexpot/commands/add_skills.py +170 -0
  27. dexpot-0.1.0/src/dexpot/requests.py +31 -0
  28. dexpot-0.1.0/src/dexpot/skills/__init__.py +1 -0
  29. dexpot-0.1.0/src/dexpot/skills/content.py +50 -0
  30. dexpot-0.1.0/src/dexpot/templates/skills/dexpot.md +153 -0
  31. dexpot-0.1.0/src/dexpot/typing_ext.py +26 -0
  32. dexpot-0.1.0/tests/test_add_skills.py +150 -0
  33. dexpot-0.1.0/tests/test_cli.py +46 -0
  34. dexpot-0.1.0/tests/test_docs.py +84 -0
  35. dexpot-0.1.0/tests/test_e2e.py +202 -0
  36. dexpot-0.1.0/tests/test_multiprocess.py +124 -0
  37. dexpot-0.1.0/tests/test_skills_content.py +68 -0
  38. dexpot-0.1.0/tests/worker_app.py +19 -0
  39. dexpot-0.1.0/uv.lock +686 -0
@@ -0,0 +1,39 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ day: "monday"
8
+ commit-message:
9
+ prefix: "chore"
10
+ include: "scope"
11
+ labels:
12
+ - "dependencies"
13
+ - "skip-changelog"
14
+
15
+ - package-ecosystem: "uv"
16
+ directory: "/"
17
+ schedule:
18
+ interval: "weekly"
19
+ day: "monday"
20
+ commit-message:
21
+ prefix: "chore"
22
+ include: "scope"
23
+ labels:
24
+ - "dependencies"
25
+ - "skip-changelog"
26
+ groups:
27
+ dev-dependencies:
28
+ patterns:
29
+ - "pytest*"
30
+ - "ruff"
31
+ - "pyright"
32
+ - "pre-commit"
33
+ - "towncrier"
34
+ - "pyyaml"
35
+ runtime-dependencies:
36
+ patterns:
37
+ - "msgspec"
38
+ - "typer"
39
+ - "httpx"
@@ -0,0 +1,33 @@
1
+ ci:
2
+ - changed-files:
3
+ - any-glob-to-any-file:
4
+ - ".github/**/*"
5
+ - "Makefile"
6
+ - ".pre-commit-config.yaml"
7
+
8
+ documentation:
9
+ - changed-files:
10
+ - any-glob-to-any-file:
11
+ - "README.md"
12
+ - "CONTRIBUTING.md"
13
+ - "ROADMAP.md"
14
+ - "docs/**/*"
15
+
16
+ source:
17
+ - changed-files:
18
+ - any-glob-to-any-file: "src/**/*"
19
+
20
+ tests:
21
+ - changed-files:
22
+ - any-glob-to-any-file: "tests/**/*"
23
+
24
+ dependencies:
25
+ - changed-files:
26
+ - any-glob-to-any-file:
27
+ - "pyproject.toml"
28
+ - "uv.lock"
29
+ - ".github/dependabot.yml"
30
+
31
+ examples:
32
+ - changed-files:
33
+ - any-glob-to-any-file: "examples/**/*"
@@ -0,0 +1,41 @@
1
+ name: Changelog
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ types: [opened, synchronize, reopened, labeled, unlabeled]
7
+
8
+ permissions:
9
+ contents: read
10
+ pull-requests: read # Required to inspect the pull request's changed files.
11
+
12
+ concurrency:
13
+ group: changelog-${{ github.event.pull_request.number }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ changelog:
18
+ name: changelog
19
+ runs-on: ubuntu-latest
20
+ timeout-minutes: 5
21
+ env:
22
+ GH_TOKEN: ${{ github.token }}
23
+ PR_NUMBER: ${{ github.event.pull_request.number }}
24
+ REPOSITORY: ${{ github.repository }}
25
+ steps:
26
+ - name: Skip non-user-facing changes
27
+ if: contains(github.event.pull_request.labels.*.name, 'skip-changelog')
28
+ run: echo "skip-changelog label present"
29
+ - name: Require this pull request's changelog fragment
30
+ if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip-changelog') }}
31
+ shell: bash
32
+ run: |
33
+ set -euo pipefail
34
+ pattern="^changelog\.d/${PR_NUMBER}\.(added|changed|deprecated|removed|fixed)\.md$"
35
+ if gh api "repos/${REPOSITORY}/pulls/${PR_NUMBER}/files" \
36
+ --paginate --jq '.[].filename' | grep -Eq "$pattern"; then
37
+ echo "changelog fragment found for PR #${PR_NUMBER}"
38
+ exit 0
39
+ fi
40
+ echo "::error::no changelog fragment for PR #${PR_NUMBER} — add changelog.d/${PR_NUMBER}.<type>.md or apply the skip-changelog label"
41
+ exit 1
@@ -0,0 +1,125 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ workflow_call:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ concurrency:
14
+ group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
15
+ cancel-in-progress: true
16
+
17
+ jobs:
18
+ lint:
19
+ name: lint
20
+ runs-on: ubuntu-latest
21
+ timeout-minutes: 10
22
+ steps:
23
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
24
+ with:
25
+ persist-credentials: false
26
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
27
+ - run: uv sync --all-extras --locked
28
+ - run: uv run ruff check src/ tests/
29
+ - run: uv run ruff format --check src/ tests/
30
+
31
+ typecheck:
32
+ name: typecheck
33
+ runs-on: ubuntu-latest
34
+ timeout-minutes: 10
35
+ steps:
36
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
37
+ with:
38
+ persist-credentials: false
39
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
40
+ - run: uv sync --all-extras --locked
41
+ - run: uv run pyright src/ tests/
42
+
43
+ test:
44
+ name: test (${{ matrix.python-version }})
45
+ runs-on: ubuntu-latest
46
+ timeout-minutes: 15
47
+ strategy:
48
+ fail-fast: false
49
+ matrix:
50
+ python-version: ["3.12", "3.13", "3.14", "3.14t"]
51
+ steps:
52
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
53
+ with:
54
+ persist-credentials: false
55
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
56
+ with:
57
+ python-version: ${{ matrix.python-version }}
58
+ - run: uv sync --all-extras --locked
59
+ - name: Verify interpreter mode
60
+ env:
61
+ EXPECTED_PYTHON: ${{ matrix.python-version }}
62
+ run: |
63
+ uv run python - <<'PY'
64
+ import os
65
+ import sys
66
+
67
+ expected = os.environ["EXPECTED_PYTHON"]
68
+ is_gil_enabled = getattr(sys, "_is_gil_enabled", lambda: True)()
69
+ print(sys.version)
70
+ print(f"gil_enabled={is_gil_enabled}")
71
+ if expected.endswith("t") and is_gil_enabled:
72
+ raise SystemExit("expected a free-threaded interpreter")
73
+ if not expected.endswith("t") and not is_gil_enabled:
74
+ raise SystemExit("expected a GIL-enabled interpreter")
75
+ PY
76
+ - run: >-
77
+ uv run pytest tests/ -v
78
+ --cov=src/dexpot
79
+ --cov-report=term-missing
80
+ --cov-fail-under=65
81
+
82
+ build:
83
+ name: build
84
+ runs-on: ubuntu-latest
85
+ timeout-minutes: 10
86
+ steps:
87
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
88
+ with:
89
+ persist-credentials: false
90
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
91
+ - run: uv build
92
+ - name: Verify distribution artifacts
93
+ run: |
94
+ python3 - <<'PY'
95
+ import glob
96
+ import tarfile
97
+ import zipfile
98
+
99
+ wheels = glob.glob("dist/*.whl")
100
+ sdists = glob.glob("dist/*.tar.gz")
101
+ assert len(wheels) == 1, f"expected one wheel, found {wheels}"
102
+ assert len(sdists) == 1, f"expected one sdist, found {sdists}"
103
+
104
+ with zipfile.ZipFile(wheels[0]) as archive:
105
+ names = archive.namelist()
106
+ for required in (
107
+ "dexpot/__init__.py",
108
+ "dexpot/templates/skills/dexpot.md",
109
+ ):
110
+ assert required in names, f"{required} missing from wheel"
111
+
112
+ with tarfile.open(sdists[0]) as archive:
113
+ names = archive.getnames()
114
+ for suffix in (
115
+ "/src/dexpot/__init__.py",
116
+ "/README.md",
117
+ "/ROADMAP.md",
118
+ "/CONTRIBUTING.md",
119
+ ):
120
+ assert any(name.endswith(suffix) for name in names), (
121
+ f"{suffix} missing from sdist"
122
+ )
123
+
124
+ print(f"verified {wheels[0]} and {sdists[0]}")
125
+ PY
@@ -0,0 +1,26 @@
1
+ name: Auto-label pull requests
2
+
3
+ on:
4
+ pull_request_target:
5
+ types: [opened, synchronize, reopened, ready_for_review]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ concurrency:
11
+ group: labeler-${{ github.event.pull_request.number }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ label:
16
+ name: label
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 5
19
+ permissions:
20
+ contents: read
21
+ pull-requests: write # Required to apply labels to pull requests.
22
+ steps:
23
+ - uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # v7.0.0
24
+ with:
25
+ repo-token: ${{ github.token }}
26
+ sync-labels: true
@@ -0,0 +1,182 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ concurrency:
11
+ group: release-${{ github.ref }}
12
+ cancel-in-progress: false
13
+
14
+ jobs:
15
+ ci:
16
+ name: CI
17
+ uses: ./.github/workflows/ci.yml
18
+
19
+ verify-version:
20
+ name: verify version and changelog
21
+ runs-on: ubuntu-latest
22
+ timeout-minutes: 5
23
+ steps:
24
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
25
+ with:
26
+ persist-credentials: false
27
+ fetch-depth: 0
28
+ - name: Verify release commit is on main
29
+ run: |
30
+ if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then
31
+ echo "::error::release tags must point to a commit reachable from main"
32
+ exit 1
33
+ fi
34
+ - name: Verify tag, package version, and changelog
35
+ env:
36
+ RELEASE_TAG: ${{ github.ref_name }}
37
+ run: |
38
+ python3 - <<'PY'
39
+ import os
40
+ import pathlib
41
+ import re
42
+ import sys
43
+ import tomllib
44
+
45
+ tag = os.environ["RELEASE_TAG"]
46
+ if not tag.startswith("v") or len(tag) == 1:
47
+ print(f"::error::release tag must be v<version>, got {tag!r}")
48
+ sys.exit(1)
49
+
50
+ version = tag[1:]
51
+ package_version = tomllib.loads(
52
+ pathlib.Path("pyproject.toml").read_text()
53
+ )["project"]["version"]
54
+ if version != package_version:
55
+ print(
56
+ f"::error::tag {tag} does not match pyproject.toml version "
57
+ f"{package_version} — run 'uv version {version}' on main first"
58
+ )
59
+ sys.exit(1)
60
+
61
+ changelog = pathlib.Path("CHANGELOG.md").read_text()
62
+ heading = re.compile(rf"^## \[{re.escape(version)}\](?:\s|$)", re.MULTILINE)
63
+ if heading.search(changelog) is None:
64
+ print(
65
+ f"::error::CHANGELOG.md has no exact '## [{version}]' section — "
66
+ "run 'make changelog' and commit it before tagging"
67
+ )
68
+ sys.exit(1)
69
+
70
+ print(f"{tag} matches pyproject.toml and CHANGELOG.md")
71
+ PY
72
+
73
+ build:
74
+ name: build release artifacts
75
+ needs: [ci, verify-version]
76
+ runs-on: ubuntu-latest
77
+ timeout-minutes: 10
78
+ steps:
79
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
80
+ with:
81
+ persist-credentials: false
82
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
83
+ with:
84
+ enable-cache: false
85
+ - run: uv build
86
+ - name: Verify release artifacts
87
+ run: |
88
+ python3 - <<'PY'
89
+ import glob
90
+ import tarfile
91
+ import zipfile
92
+
93
+ wheels = glob.glob("dist/*.whl")
94
+ sdists = glob.glob("dist/*.tar.gz")
95
+ assert len(wheels) == 1, f"expected one wheel, found {wheels}"
96
+ assert len(sdists) == 1, f"expected one sdist, found {sdists}"
97
+ with zipfile.ZipFile(wheels[0]) as archive:
98
+ names = archive.namelist()
99
+ assert "dexpot/__init__.py" in names
100
+ assert "dexpot/templates/skills/dexpot.md" in names
101
+ with tarfile.open(sdists[0]) as archive:
102
+ names = archive.getnames()
103
+ assert any(name.endswith("/src/dexpot/__init__.py") for name in names)
104
+ assert any(name.endswith("/ROADMAP.md") for name in names)
105
+ print(f"verified {wheels[0]} and {sdists[0]}")
106
+ PY
107
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
108
+ with:
109
+ name: dist
110
+ path: dist/
111
+ if-no-files-found: error
112
+
113
+ publish:
114
+ name: publish to PyPI
115
+ needs: build
116
+ runs-on: ubuntu-latest
117
+ timeout-minutes: 10
118
+ environment: pypi
119
+ permissions:
120
+ contents: read
121
+ id-token: write # Required for PyPI trusted publishing through OIDC.
122
+ steps:
123
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
124
+ with:
125
+ name: dist
126
+ path: dist/
127
+ - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
128
+ with:
129
+ attestations: true
130
+
131
+ github-release:
132
+ name: create GitHub Release
133
+ needs: publish
134
+ runs-on: ubuntu-latest
135
+ timeout-minutes: 10
136
+ permissions:
137
+ contents: write # Required to create the GitHub Release and upload assets.
138
+ steps:
139
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
140
+ with:
141
+ persist-credentials: false
142
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
143
+ with:
144
+ name: dist
145
+ path: dist/
146
+ - name: Extract release notes from changelog
147
+ env:
148
+ RELEASE_VERSION: ${{ github.ref_name }}
149
+ run: |
150
+ python3 - <<'PY' > release-notes.md
151
+ import os
152
+ import pathlib
153
+ import re
154
+ import sys
155
+
156
+ version = os.environ["RELEASE_VERSION"].removeprefix("v")
157
+ text = pathlib.Path("CHANGELOG.md").read_text()
158
+ match = re.search(
159
+ rf"^## \[{re.escape(version)}\][^\n]*\n(.*?)(?=^## \[|\Z)",
160
+ text,
161
+ re.MULTILINE | re.DOTALL,
162
+ )
163
+ if match is None:
164
+ sys.exit(f"no exact '## [{version}]' section in CHANGELOG.md")
165
+ print(match.group(1).strip())
166
+ PY
167
+ cat release-notes.md
168
+ - name: Create GitHub Release
169
+ env:
170
+ GH_TOKEN: ${{ github.token }}
171
+ RELEASE_TAG: ${{ github.ref_name }}
172
+ run: |
173
+ set -euo pipefail
174
+ version="${RELEASE_TAG#v}"
175
+ args=()
176
+ case "$version" in *-*) args+=(--prerelease) ;; esac
177
+ gh release create "$RELEASE_TAG" \
178
+ --title "$RELEASE_TAG" \
179
+ --notes-file release-notes.md \
180
+ --verify-tag \
181
+ "${args[@]}" \
182
+ dist/*
@@ -0,0 +1,40 @@
1
+ name: Stale issue and pull request management
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "30 1 * * *"
6
+ workflow_dispatch:
7
+
8
+ permissions: {}
9
+
10
+ concurrency:
11
+ group: stale-management
12
+ cancel-in-progress: false
13
+
14
+ jobs:
15
+ stale:
16
+ name: stale
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 10
19
+ permissions:
20
+ issues: write # Required to label, comment on, and close stale issues.
21
+ pull-requests: write # Required to manage stale pull requests.
22
+ steps:
23
+ - uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0
24
+ with:
25
+ stale-issue-message: >
26
+ This issue has been marked stale because it has not had recent activity.
27
+ It will close in 14 days unless new information is added.
28
+ stale-pr-message: >
29
+ This pull request has been marked stale because it has not had recent activity.
30
+ It will close in 14 days unless work resumes.
31
+ close-issue-message: This issue was closed due to inactivity.
32
+ close-pr-message: This pull request was closed due to inactivity.
33
+ stale-issue-label: stale
34
+ stale-pr-label: stale
35
+ days-before-stale: 60
36
+ days-before-close: 14
37
+ days-before-pr-stale: 30
38
+ days-before-pr-close: 14
39
+ exempt-issue-labels: enhancement,pinned,security
40
+ exempt-pr-labels: pinned,security,dependencies
@@ -0,0 +1,15 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .venv/
8
+ .venv-ft/
9
+ .pytest_cache/
10
+ .ruff_cache/
11
+ .coverage
12
+ htmlcov/
13
+
14
+ # tooling
15
+ .DS_Store
@@ -0,0 +1,14 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.16.4
4
+ hooks:
5
+ - id: ruff-check
6
+ args: [--fix]
7
+ - id: ruff-format
8
+ - repo: https://github.com/pre-commit/pre-commit-hooks
9
+ rev: v6.0.0
10
+ hooks:
11
+ - id: check-toml
12
+ - id: check-yaml
13
+ - id: end-of-file-fixer
14
+ - id: trailing-whitespace
@@ -0,0 +1,22 @@
1
+ # Changelog
2
+
3
+ All notable changes to dexpot will be documented in this file.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions
6
+ follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ Unreleased changes live as files in [`changelog.d/`](changelog.d/) until release
9
+ preparation assembles them here. Run `make changelog-draft` to preview the next release.
10
+
11
+ <!-- towncrier release notes start -->
12
+
13
+ ## [0.1.0] - 2026-08-25
14
+
15
+ ### Added
16
+
17
+ - Add the initial dexpot serving core, typed routing API, adaptive scheduler, CLI, tests, and CI. ([#1](https://github.com/tugrulguner/dexpot/pull/1))
18
+ - Add `dexpot add skills` for six coding agents, expanded framework documentation and roadmap, and release-ready repository automation. ([#3](https://github.com/tugrulguner/dexpot/pull/3))
19
+
20
+ ### Changed
21
+
22
+ - Add compiled endpoint plans, duplicate-route detection, and DEXPOT_WORKERS multiprocess serving on GIL builds. ([#2](https://github.com/tugrulguner/dexpot/pull/2))
@@ -0,0 +1,95 @@
1
+ # Contributing to dexpot
2
+
3
+ Thanks for helping build dexpot as a synchronous API framework for GIL and free-threaded
4
+ CPython.
5
+
6
+ ## Development setup
7
+
8
+ ```bash
9
+ git clone https://github.com/tugrulguner/dexpot.git
10
+ cd dexpot
11
+ uv sync --all-extras
12
+ uv run pre-commit install
13
+ make check
14
+ ```
15
+
16
+ Use `make format` before committing.
17
+
18
+ ## What a change must preserve
19
+
20
+ - Plain synchronous handlers; no coroutine bridge in the request path.
21
+ - Route and argument errors fail during registration when they can be known then.
22
+ - A worker owns a keep-alive connection until close.
23
+ - GIL admission remains bounded and returns 503 instead of accumulating unlimited work.
24
+ - Free-threaded and GIL behavior are tested deliberately rather than assumed equivalent.
25
+ - Public performance claims come from reproducible, correctness-matched benchmarks.
26
+
27
+ The rules above come from the route-binding, keep-alive, signal, and multiprocess bugs
28
+ already exercised by the end-to-end suite. Treat them as architecture contracts rather
29
+ than style preferences.
30
+
31
+ ## Tests
32
+
33
+ Run the complete gate:
34
+
35
+ ```bash
36
+ make check
37
+ ```
38
+
39
+ The gate includes lint, formatting, type checking, real HTTP tests, and coverage. Useful
40
+ narrower commands are:
41
+
42
+ ```bash
43
+ uv run pytest tests/test_e2e.py -v
44
+ uv run pytest tests/test_multiprocess.py -v
45
+ uv run pytest tests/test_add_skills.py tests/test_skills_content.py -v
46
+ ```
47
+
48
+ A behavior change needs an end-to-end test against the real socket server. A unit test of a
49
+ private helper is not enough by itself. Multiprocess, signal, restart, and drain behavior
50
+ must run in a subprocess because Python only permits signal handlers in the main thread.
51
+
52
+ ## Pull requests
53
+
54
+ 1. Branch from the latest `main`.
55
+ 2. Keep the change focused on one concern.
56
+ 3. Add or update real-user tests and executable examples when behavior changes.
57
+ 4. Update README, roadmap, agent skill, and contributor guidance in the same change when
58
+ their contract changes.
59
+ 5. Add a changelog fragment for a user-facing change.
60
+ 6. Run `make check`, `make build`, and the workflow checks in
61
+ [`docs/reviewing.md`](docs/reviewing.md).
62
+ 7. Open a pull request with the current behavior, the change, and verification evidence.
63
+
64
+ ## Changelog fragments
65
+
66
+ User-facing changes require one file named for the pull request:
67
+
68
+ ```text
69
+ changelog.d/<pr-number>.<type>.md
70
+ ```
71
+
72
+ Types are `added`, `changed`, `deprecated`, `removed`, and `fixed`. Write one sentence about
73
+ what changed for a user. Do not edit `CHANGELOG.md` directly; Towncrier assembles it during
74
+ release preparation. For maintenance with no user-visible effect, a maintainer may apply
75
+ the `skip-changelog` label.
76
+
77
+ ## Releasing
78
+
79
+ Maintainers follow [`docs/releasing.md`](docs/releasing.md). Do not bump the version or tag a
80
+ feature pull request. `pyproject.toml` is the one editable version source; `uv version`
81
+ updates it and the lockfile together.
82
+
83
+ ## Reporting issues
84
+
85
+ Search existing issues first. A useful bug report includes:
86
+
87
+ - Python version and whether `sys._is_gil_enabled()` is true or false;
88
+ - operating system;
89
+ - a minimal runnable application;
90
+ - the exact request and observed response;
91
+ - concurrency settings such as `DEXPOT_POOL`, `DEXPOT_MAX_QUEUE`, and `DEXPOT_WORKERS`;
92
+ - whether the failure reproduces with a single connection and a single process.
93
+
94
+ For substantial API or scheduler changes, open an issue and align on the contract before
95
+ implementation.
dexpot-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tugrul Guner
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.