oe-sdk 0.1.0a1__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 (47) hide show
  1. oe_sdk-0.1.0a1/.agents/skills/generate-adr/SKILL.md +233 -0
  2. oe_sdk-0.1.0a1/.agents/skills/generate-adr/evals/evals.json +33 -0
  3. oe_sdk-0.1.0a1/.agents/skills/generate-adr/references/anti-patterns.md +90 -0
  4. oe_sdk-0.1.0a1/.agents/skills/generate-adr/references/madr-template.md +100 -0
  5. oe_sdk-0.1.0a1/.github/copilot-instructions.md +431 -0
  6. oe_sdk-0.1.0a1/.github/workflows/ci.yml +202 -0
  7. oe_sdk-0.1.0a1/.github/workflows/nightly-integration.yml +68 -0
  8. oe_sdk-0.1.0a1/.github/workflows/publish-wiki.yml +22 -0
  9. oe_sdk-0.1.0a1/.github/workflows/publish.yml +23 -0
  10. oe_sdk-0.1.0a1/.gitignore +220 -0
  11. oe_sdk-0.1.0a1/.python-version +1 -0
  12. oe_sdk-0.1.0a1/CONTRIBUTING.md +179 -0
  13. oe_sdk-0.1.0a1/LICENSE +191 -0
  14. oe_sdk-0.1.0a1/PKG-INFO +281 -0
  15. oe_sdk-0.1.0a1/README.md +72 -0
  16. oe_sdk-0.1.0a1/docs/decisions/0001-modular-package-with-optional-extras-per-module.md +79 -0
  17. oe_sdk-0.1.0a1/docs/decisions/0002-pydantic-v2-for-configuration-models.md +88 -0
  18. oe_sdk-0.1.0a1/docs/decisions/0003-expose-raw-upstream-clients-no-wrappers-no-custom-exceptions.md +78 -0
  19. oe_sdk-0.1.0a1/docs/decisions/0004-native-sync-and-async-variants-per-io-module.md +84 -0
  20. oe_sdk-0.1.0a1/docs/decisions/0005-multi-use-context-managed-lifecycle-for-io-clients.md +62 -0
  21. oe_sdk-0.1.0a1/docs/decisions/0006-uv-as-build-backend-and-dependency-toolchain.md +99 -0
  22. oe_sdk-0.1.0a1/docs/decisions/0007-support-every-non-eol-cpython-minor.md +86 -0
  23. oe_sdk-0.1.0a1/docs/decisions/README.md +31 -0
  24. oe_sdk-0.1.0a1/prek.toml +27 -0
  25. oe_sdk-0.1.0a1/pyproject.toml +116 -0
  26. oe_sdk-0.1.0a1/src/oe_sdk/__init__.py +10 -0
  27. oe_sdk-0.1.0a1/src/oe_sdk/py.typed +0 -0
  28. oe_sdk-0.1.0a1/src/oe_sdk/s3/README.md +204 -0
  29. oe_sdk-0.1.0a1/src/oe_sdk/s3/__init__.py +30 -0
  30. oe_sdk-0.1.0a1/src/oe_sdk/s3/_aio.py +159 -0
  31. oe_sdk-0.1.0a1/src/oe_sdk/s3/_client.py +151 -0
  32. oe_sdk-0.1.0a1/src/oe_sdk/s3/_types.py +42 -0
  33. oe_sdk-0.1.0a1/src/oe_sdk/s3/_utils.py +55 -0
  34. oe_sdk-0.1.0a1/tests/s3/__init__.py +0 -0
  35. oe_sdk-0.1.0a1/tests/s3/integration/__init__.py +0 -0
  36. oe_sdk-0.1.0a1/tests/s3/integration/test_aio_localstack.py +47 -0
  37. oe_sdk-0.1.0a1/tests/s3/test_aio.py +173 -0
  38. oe_sdk-0.1.0a1/tests/s3/test_client.py +209 -0
  39. oe_sdk-0.1.0a1/tests/s3/test_utils.py +56 -0
  40. oe_sdk-0.1.0a1/tests/test_top_level_package.py +60 -0
  41. oe_sdk-0.1.0a1/uv.lock +1829 -0
  42. oe_sdk-0.1.0a1/wiki/Contributing.md +115 -0
  43. oe_sdk-0.1.0a1/wiki/Design-Principles.md +98 -0
  44. oe_sdk-0.1.0a1/wiki/Getting-Started.md +84 -0
  45. oe_sdk-0.1.0a1/wiki/Home.md +47 -0
  46. oe_sdk-0.1.0a1/wiki/Python-Support-and-Releases.md +66 -0
  47. oe_sdk-0.1.0a1/wiki/S3-Module.md +174 -0
@@ -0,0 +1,233 @@
1
+ ---
2
+ name: generate-adr
3
+ description: |
4
+ Analyse changes on the current branch (versus the default branch) and draft
5
+ Markdown Architectural Decision Records (MADRs) into docs/decisions/.
6
+ Surfaces the architecturally significant choices made on the branch, proposes
7
+ one ADR per distinct decision, and writes NNNN-title.md files using the MADR
8
+ 4.x template. Use whenever the user wants to record design rationale from a
9
+ branch, capture architecture decisions before opening a PR, produce ADRs, or
10
+ document a technology/library/pattern choice that has just landed in the
11
+ diff, even if the user does not explicitly say "ADR".
12
+ ---
13
+
14
+ <aim>
15
+
16
+ Turn a branch's diff into durable design rationale. Read the changes versus
17
+ the default branch, spot the architecturally significant decisions, and write
18
+ them up as MADR-format records in `docs/decisions/`. One ADR per distinct
19
+ decision, numbered, assertive, and honest about trade-offs. Follow the spirit
20
+ of Olaf Zimmermann's ADR creation guidance: brief executive summaries,
21
+ considered options with real trade-offs, and a clear verdict.
22
+
23
+ </aim>
24
+
25
+ <preflight>
26
+
27
+ Run these checks first. Stop and report clearly if any fail.
28
+
29
+ 1. **Inside a git repo with a clean enough state to diff:**
30
+ ```bash
31
+ git rev-parse --is-inside-work-tree
32
+ ```
33
+
34
+ 2. **Not on the default branch** (nothing to diff against otherwise):
35
+ ```bash
36
+ git branch --show-current
37
+ ```
38
+ If the output matches the repo's default branch (`main`, `master`, or
39
+ whatever `origin/HEAD` resolves to), stop:
40
+ > "You're on the default branch, so there's no branch diff to analyse.
41
+ > Switch to a feature branch and rerun."
42
+
43
+ 3. **Default branch is resolvable:**
44
+ ```bash
45
+ git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||'
46
+ ```
47
+ If this is empty, fall back to `main`. If `main` does not exist locally,
48
+ ask the user what the base branch should be.
49
+
50
+ </preflight>
51
+
52
+ ## Workflow
53
+
54
+ ### Step 1: Locate (or choose) the ADR directory
55
+
56
+ Probe for an existing ADR location in this order:
57
+
58
+ 1. `docs/decisions/` (MADR's own convention)
59
+ 2. `docs/adr/`
60
+ 3. `docs/architecture/decisions/`
61
+ 4. `adr/` at repo root
62
+ 5. Any directory matching `**/NNNN-*.md` where `NNNN` is four digits
63
+
64
+ If more than one exists, use the one with the most files. If none exist,
65
+ default to `docs/decisions/` and create it on write.
66
+
67
+ Record the chosen directory. Scan it for the highest existing `NNNN` prefix
68
+ so the next ADR picks up from `NNNN + 1` (zero-padded to four digits).
69
+
70
+ ### Step 2: Gather branch context
71
+
72
+ Run these in parallel:
73
+
74
+ ```bash
75
+ BASE=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||')
76
+ BASE=${BASE:-main}
77
+
78
+ if git show-ref --verify --quiet "refs/remotes/origin/${BASE}"; then
79
+ BASE_REF="origin/${BASE}"
80
+ elif git show-ref --verify --quiet "refs/heads/${BASE}"; then
81
+ BASE_REF="${BASE}"
82
+ else
83
+ echo "Could not resolve base branch: ${BASE}" >&2
84
+ exit 1
85
+ fi
86
+
87
+ git log --no-pager "${BASE_REF}..HEAD" --oneline
88
+ git diff --no-pager --stat "${BASE_REF}...HEAD"
89
+ git diff --no-pager "${BASE_REF}...HEAD"
90
+ ```
91
+
92
+ ### Step 3: Identify architecturally significant decisions
93
+
94
+ Read the diff and extract the decisions that deserve a record. Signals to
95
+ look for, roughly in descending order of significance:
96
+
97
+ - New or swapped runtime dependencies (package.json, pyproject.toml,
98
+ requirements.txt, go.mod, Cargo.toml, Gemfile, etc.)
99
+ - New top-level modules, packages, or services
100
+ - Database schema changes, new migrations, new storage engines
101
+ - New or changed external contracts: API endpoints, event schemas,
102
+ message formats, SDK versions
103
+ - Infrastructure changes: Terraform, Helm, Dockerfiles, CI configs that
104
+ shift where or how the system runs
105
+ - Replacement of an existing implementation (the "we used X, now we use Y"
106
+ shape)
107
+ - Introduction of a new cross-cutting pattern: caching, async/queues,
108
+ auth/authz, feature flags, observability
109
+ - Non-trivial changes to shared abstractions, base classes, or protocols
110
+
111
+ Ignore pure refactors, formatting, lockfile-only changes, and typo fixes
112
+ unless the commit messages frame them as intentional decisions.
113
+
114
+ Group related changes into a single decision. A single ADR can span many
115
+ files if they all serve one choice (e.g. "adopt Redis for rate limiting"
116
+ might touch code, tests, Helm values, and a dependency file). Don't split
117
+ one decision into multiple ADRs just because it is wide.
118
+
119
+ ### Step 4: Propose the ADR slate
120
+
121
+ Present the proposed ADRs to the user as a short list. For each entry give:
122
+
123
+ - A working title (imperative, specific, no filler)
124
+ - One sentence framing the problem
125
+ - The files or areas of the diff that motivate it
126
+
127
+ Then ask:
128
+
129
+ > "Here's what I'd like to record. Shall I draft all of them, or do you want
130
+ > to drop, merge, or add any? You can also tell me to write a specific one
131
+ > first."
132
+
133
+ Honour edits. If the user merges two proposals, keep the combined decision's
134
+ scope in mind when drafting. If they drop one, drop it fully.
135
+
136
+ ### Step 5: For each approved decision, draft the ADR
137
+
138
+ Follow the MADR 4.x template (see `references/madr-template.md` for the
139
+ full canonical form). Every ADR must have:
140
+
141
+ - YAML frontmatter with `status: proposed`, `date: <today, YYYY-MM-DD>`,
142
+ and `decision-makers` set to the branch's commit authors (dedup, drop
143
+ `[bot]` accounts).
144
+ - A short, descriptive H1 title.
145
+ - `## Context and Problem Statement` — two or three sentences. Use terms
146
+ from the domain vocabulary visible in the diff. Frame the problem as a
147
+ question where possible; you want readers curious.
148
+ - `## Decision Drivers` — bullets covering the forces that shaped the
149
+ decision (quality attributes, constraints, existing conventions in the
150
+ repo). Keep them specific to the situation, not generic.
151
+ - `## Considered Options` — at least two, ideally three. One of them must
152
+ be a real alternative; placeholder "do nothing" options are fine only if
153
+ they genuinely reflect a status quo worth weighing. Read the diff for
154
+ clues about what was *not* chosen (e.g. imports that were considered,
155
+ libraries mentioned in comments, removed code that hints at prior attempts).
156
+ - `## Decision Outcome` — a single sentence naming the chosen option and
157
+ the primary reason. Assertive voice. No hedging.
158
+ - `### Consequences` — mix good and bad, at least one of each. Cover
159
+ operational and maintenance impact, not only developer ergonomics.
160
+ - `### Confirmation` — how you'd verify the decision was actually adopted
161
+ (tests, metrics, CI checks, code review rules). Concrete if possible.
162
+ - `## Pros and Cons of the Options` — one subsection per considered option
163
+ with a short description plus bulleted pros and cons. This is what lets a
164
+ reader in six months see the trade-space.
165
+ - `## More Information` — optional. Only include links and references that
166
+ genuinely help (issue trackers, vendor docs, prior ADRs). Skip if empty;
167
+ don't pad.
168
+
169
+ File name: `NNNN-title-with-dashes.md`, lowercase, four-digit prefix
170
+ continuing the repo's sequence, kebab-case title derived from the ADR's H1.
171
+
172
+ ### Step 6: Write each ADR and confirm
173
+
174
+ Write the files with `mkdir -p <adr-dir>` as needed. Then summarise back to
175
+ the user:
176
+
177
+ ```
178
+ Drafted <N> ADR(s) in <adr-dir>:
179
+ <NNNN>-<slug>.md — <title>
180
+ ...
181
+
182
+ Each is marked `status: proposed`. Review, edit as you see fit, and flip the
183
+ status to `accepted` when you're ready.
184
+ ```
185
+
186
+ ### Step 7: Offer to commit
187
+
188
+ Ask the user whether they'd like the ADRs committed to the current branch:
189
+
190
+ > "Do you want me to commit these ADRs to the current branch? I'll only stage
191
+ > the new files, not anything else you have in flight. Reply 'yes' to commit,
192
+ > or 'no' to leave them unstaged for you to handle."
193
+
194
+ If the user says yes:
195
+
196
+ ```bash
197
+ git add <adr-dir>/<NNNN>-<slug>.md ...
198
+ git commit -m "docs(adr): add <N> ADR(s) for <branch-name>" \
199
+ -m "<bullet list of ADR titles>"
200
+ ```
201
+
202
+ Use only the new ADR paths in the `git add` invocation so nothing else the
203
+ user has staged or modified gets pulled in. Report the commit SHA back.
204
+
205
+ If the user says no (or anything other than yes), leave the files on disk
206
+ unstaged and confirm:
207
+
208
+ > "Left the ADRs unstaged. Review and commit when you're ready."
209
+
210
+ Do not push. Do not open a PR. That's a separate workflow.
211
+
212
+ ## Tone and quality guardrails
213
+
214
+ Before you finalise each ADR, check it against the anti-patterns in
215
+ `references/anti-patterns.md`. Specifically:
216
+
217
+ - No marketing language or unsubstantiated superlatives.
218
+ - At least one real alternative, not a straw-man.
219
+ - Cost and risk stated alongside benefit.
220
+ - Confidence level honest; if you're unsure, say `status: proposed` and
221
+ note the uncertainty in `## More Information`.
222
+ - Keep the whole thing tight. If a section has nothing to say, omit it.
223
+ Empty headings are worse than no heading.
224
+
225
+ The ADR is meant to read like a journal entry from the decision maker:
226
+ specific, grounded in the actual diff, and useful to whoever reads it next
227
+ quarter when something breaks.
228
+
229
+ ## Reference files
230
+
231
+ - `references/madr-template.md` — full MADR 4.x template with placeholders.
232
+ - `references/anti-patterns.md` — Zimmermann's ADR anti-patterns with
233
+ examples; consult before finalising any ADR.
@@ -0,0 +1,33 @@
1
+ {
2
+ "skill_name": "generate-adr",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "name": "single-decision-library-swap",
7
+ "prompt": "I'm on a feature branch where I swapped our in-house retry logic for the `tenacity` library across the HTTP client layer. I've also added `tenacity>=8.2` to pyproject.toml, removed the old retry/ module, and updated three call sites. Generate any ADRs you think this branch warrants.",
8
+ "expected_output": "A single ADR in docs/decisions/ (NNNN-<slug>.md) using MADR format, capturing the decision to adopt tenacity over the in-house retry helper. Should include at least two considered options (tenacity, keep in-house, optionally backoff/other libs), real trade-offs, and a confirmation strategy. Skill should also ask whether to commit.",
9
+ "files": []
10
+ },
11
+ {
12
+ "id": 2,
13
+ "name": "multi-decision-branch",
14
+ "prompt": "This branch does two things: (1) introduces Redis for distributed rate limiting (new redis dependency, new helm values block, new RateLimiter abstraction) and (2) moves our background jobs off threading onto asyncio with a new asyncio.TaskGroup-based runner. Record these properly.",
15
+ "expected_output": "Two separate ADRs in docs/decisions/, numbered sequentially. One for the Redis-based rate limiter decision, one for the asyncio concurrency model. Each self-contained, neither trying to cover the other. Skill should also ask whether to commit.",
16
+ "files": []
17
+ },
18
+ {
19
+ "id": 3,
20
+ "name": "database-technology-choice",
21
+ "prompt": "I'm introducing a new service that needs a primary datastore. On this branch I've picked Postgres, added migrations, and wired up SQLAlchemy. Draft the ADR.",
22
+ "expected_output": "A single ADR using MADR. Must name at least two real alternatives (e.g. MySQL, SQLite, a managed option, or a document store) rather than a straw-man. Decision drivers should reference operational concerns (backups, team familiarity, managed service availability), not just developer ergonomics.",
23
+ "files": []
24
+ },
25
+ {
26
+ "id": 4,
27
+ "name": "refactor-only-branch",
28
+ "prompt": "This branch renames a bunch of functions, moves some modules around, and fixes typos. Generate ADRs for it.",
29
+ "expected_output": "The skill should recognise there are no architecturally significant decisions here and respond by saying so, rather than inventing an ADR. If it does write anything, it should be at most one ADR clearly scoped to a meaningful decision, not one per rename.",
30
+ "files": []
31
+ }
32
+ ]
33
+ }
@@ -0,0 +1,90 @@
1
+ # ADR anti-patterns
2
+
3
+ Adapted from Olaf Zimmermann's "How to create Architectural Decision Records
4
+ — and how not to" (ozimmer.ch, 2023). Consult this list before finalising
5
+ any ADR. If a draft smells like one of these, rewrite it.
6
+
7
+ ## Subjectivity patterns
8
+
9
+ ### Fairy Tale (Wishful Thinking)
10
+
11
+ A shallow justification with only upsides. Pros listed, cons absent.
12
+
13
+ Bad: "We decided for a load balancer because it balances load, which is a
14
+ good thing."
15
+
16
+ Fix: name at least one concrete cost, risk, or trade-off. If you truly can't
17
+ find one, you're not looking hard enough, or the decision isn't worth a
18
+ record.
19
+
20
+ ### Sales Pitch
21
+
22
+ Marketing language. Adjectives and adverbs that can't be backed by evidence.
23
+
24
+ Bad: "We chose this outstanding technology because it is unrivalled in the
25
+ marketplace; its splendid performance shines everywhere."
26
+
27
+ Fix: delete every adjective and adverb you can't substantiate. Link to the
28
+ benchmark, issue tracker, or prior experience that supports the claim, or
29
+ remove the claim.
30
+
31
+ ### Free Lunch Coupon
32
+
33
+ No consequences documented, or only trivially harmless ones. Long-term and
34
+ operational costs hidden.
35
+
36
+ Bad: "We decided for event-based architecture because it decouples the
37
+ communication participants."
38
+
39
+ Fix: explicitly name the design, test, and operational cost. Mention who
40
+ pays it (developers, on-call, consumers of the API).
41
+
42
+ ### Dummy Alternative
43
+
44
+ A fake option to make the preferred choice shine.
45
+
46
+ Bad: "We decided to use Postgres. We could implement our own relational
47
+ database, but this takes time and effort."
48
+
49
+ Fix: find a real alternative. For most decisions there's at least one
50
+ industry-standard competitor worth naming. If there genuinely isn't,
51
+ explain why — that's the actual decision.
52
+
53
+ ## Time-dimension patterns
54
+
55
+ ### Sprint (Rush)
56
+
57
+ Only one option. Only short-term consequences considered.
58
+
59
+ Fix: search for alternatives (online, professional networks, the team's own
60
+ history). Report on the search, even briefly. Add at least a sentence on
61
+ mid-term consequences.
62
+
63
+ ### Tunnel Vision
64
+
65
+ Local view only. Developer experience covered, operations and maintenance
66
+ ignored.
67
+
68
+ Fix: name sysadmins, SREs, and maintainers explicitly in Decision Drivers
69
+ or Consequences. Score the chosen solution against manageability and
70
+ evolvability.
71
+
72
+ ### Maze
73
+
74
+ Topic drifts. Discussion centres on irrelevant detail.
75
+
76
+ Fix: keep the title and problem statement in view while writing. If a
77
+ paragraph doesn't serve the stated question, cut it.
78
+
79
+ ## Quality checklist
80
+
81
+ Before marking an ADR ready for review:
82
+
83
+ - Does every adjective earn its place?
84
+ - Is there at least one genuine alternative?
85
+ - Is there at least one real trade-off in Consequences?
86
+ - Would an operator or maintainer recognise their concerns in the ADR?
87
+ - If someone asked "why this, not that?" in review, is the answer already
88
+ in the document?
89
+ - Is the word count proportionate to the stakes? One page for routine
90
+ choices; a few pages only when the problem is genuinely wicked.
@@ -0,0 +1,100 @@
1
+ # MADR 4.x Template
2
+
3
+ Use this as the canonical template when drafting a new ADR. Remove any
4
+ optional sections (marked below) that you don't need, rather than leaving
5
+ them empty.
6
+
7
+ ```markdown
8
+ ---
9
+ # status options: proposed | rejected | accepted | deprecated | superseded by ADR-NNNN
10
+ status: proposed
11
+ date: YYYY-MM-DD
12
+ decision-makers: [list of people involved in the decision]
13
+ # consulted: [optional list of SMEs and others with two-way communication]
14
+ # informed: [optional list of people kept up-to-date, one-way communication]
15
+ ---
16
+
17
+ # {short title, representative of solved problem and found solution}
18
+
19
+ ## Context and Problem Statement
20
+
21
+ {Describe the context and problem statement in two or three sentences, or as
22
+ an illustrative story. Frame the problem as a question where possible, and
23
+ link to issue trackers or design docs where useful.}
24
+
25
+ ## Decision Drivers
26
+
27
+ * {driver 1, e.g. a force, facing concern, quality attribute}
28
+ * {driver 2}
29
+ * ...
30
+
31
+ ## Considered Options
32
+
33
+ * {title of option 1}
34
+ * {title of option 2}
35
+ * {title of option 3}
36
+
37
+ ## Decision Outcome
38
+
39
+ Chosen option: "{title of option 1}", because {justification: e.g. only
40
+ option that meets a k.o. criterion; resolves a key driver; comes out best
41
+ when weighed against the others}.
42
+
43
+ ### Consequences
44
+
45
+ * Good, because {positive consequence, e.g. improvement of a desired quality}
46
+ * Bad, because {negative consequence, e.g. cost, complexity, new failure mode}
47
+ * ...
48
+
49
+ ### Confirmation
50
+
51
+ {How will implementation of and compliance with this decision be confirmed?
52
+ Code review rules, automated tests, CI checks, a dashboard metric, a runbook
53
+ reference. Concrete if possible.}
54
+
55
+ ## Pros and Cons of the Options
56
+
57
+ ### {title of option 1}
58
+
59
+ {description, 1-2 sentences, or a link}
60
+
61
+ * Good, because {argument}
62
+ * Good, because {argument}
63
+ * Neutral, because {argument}
64
+ * Bad, because {argument}
65
+
66
+ ### {title of option 2}
67
+
68
+ {description}
69
+
70
+ * Good, because {argument}
71
+ * Bad, because {argument}
72
+
73
+ ### {title of option 3}
74
+
75
+ {description}
76
+
77
+ * Good, because {argument}
78
+ * Bad, because {argument}
79
+
80
+ ## More Information
81
+
82
+ {Optional. Links to related ADRs, vendor documentation, benchmarks, issue
83
+ trackers, prior art. Omit the section entirely if there's nothing worth
84
+ linking.}
85
+ ```
86
+
87
+ ## File naming
88
+
89
+ - Pattern: `NNNN-title-with-dashes.md`
90
+ - `NNNN` is a zero-padded four-digit sequence (`0001`, `0002`, ...)
91
+ - Title is kebab-case, lowercase, derived from the ADR's H1
92
+ - Example: `0007-use-postgres-for-rate-limiter-state.md`
93
+
94
+ ## Status lifecycle
95
+
96
+ - `proposed` — drafted, not yet agreed
97
+ - `accepted` — agreed and being enacted
98
+ - `rejected` — considered and ruled out
99
+ - `deprecated` — no longer applicable
100
+ - `superseded by ADR-NNNN` — a later ADR replaces this one