Imported from yeongseon/azure-functions-knowledge-python (
AGENTS.md). Install upstream withnpx skills add yeongseon/azure-functions-knowledge-python. Copyright stays with the author.
AGENTS.md
Purpose
azure-functions-knowledge-python provides knowledge retrieval (RAG) decorators for Azure Functions Python v2 applications.
Repository Identity
- Project:
azure-functions-knowledge - Project type: Python library
- Runtime scope: Azure Functions Python v2 programming model
- Minimum supported Python:
3.10 - Packaging:
pyproject.tomlwith Hatch
Read First
README.mdCONTRIBUTING.mddocs/agent-playbook.md
Working Rules
Test Coverage
- Maintain test coverage at 95% or above for committed changes and PRs.
- Run
hatch run pytest --cov --cov-report=term-missing -qto verify before submitting changes. - Any PR that drops coverage below 95% must include additional tests to compensate.
- Preserve the package's Python compatibility and public API behavior unless the change explicitly updates the contract.
- Keep documentation, examples, and tests synchronized.
- Never suppress type errors.
- Provider implementations must conform to the
KnowledgeProviderprotocol.
Documentation & Translations
- English (
README.md) is the canonical source of truth for all documentation. Translated READMEs (README.ko.md,README.ja.md,README.zh-CN.md) are best-effort, community-maintained, and may lag the English source. - Translation sync is not required in the same PR as an English change, and a PR is never blocked by translation drift. Update translations opportunistically; when you do, keep them faithful to the current English source.
- Each translated README carries a staleness banner linking back to the canonical English README. Keep that banner in place so readers always know the translation may be out of date.
Action Pinning
- Pin every external GitHub Action
uses:reference in.github/workflows/to a full commit SHA with a# vX.Y.Zcomment. - Only local composite actions (
uses: ./...) and the PyPA publish action (pypa/gh-action-pypi-publish) may skip SHA pinning; document any exception with an inline comment at the call site. - Dependabot updates SHA-pinned references on the configured schedule and opens PRs when new versions are available.
PR Workflow
Always issue-first. Before opening any PR:
- Run
gh issue listto check whether a tracking issue already exists for the change. - If no issue exists, create one following the Issue Conventions below before writing any code.
- Open the PR only after the issue exists. The PR body must include
Closes #Nfor every issue it resolves — never open a PR that cannot be traced back to an issue.
Non-negotiable: a PR without a linked issue will be rejected at review.
Issue Conventions
Follow these conventions when opening issues so the backlog stays consistent with sibling DX Toolkit repositories.
Title
- Use Conventional Commit prefixes:
feat:,fix:,docs:,refactor:,test:,chore:,ci:,build:,perf:. - Add a scope qualifier when it narrows the area:
feat(provider):,docs(notion):,refactor(bindings):. - Keep the title imperative, under ~80 characters, no trailing period.
- Do not put a priority marker in the title — priority is tracked with a
priority:*label.
Body
Use the following sections, in order, omitting any that do not apply:
## Context
What problem this issue addresses and why now. Note the target release (e.g. vX.Y.Z) here if known.
## Acceptance Checklist
- [ ] Concrete, verifiable items.
## Out of scope
- Items intentionally excluded, with links to the issues that track them.
## References
- PRs, ADRs, sibling issues, external docs.
Labels
- Apply at least one of
bug,enhancement,documentation,chore. - Apply exactly one priority label. The scale in use is
priority:critical/priority:high/priority:medium/priority:low;criticalis reserved for defects that reach package users, such as a broken published artifact or wrong product output. - Labels are applied by maintainers or authorized triage automation. An external contributor without label permissions should describe urgency in the issue body and leave labelling to triage.
- Add
area:*labels when they exist in the repository. - Use
blockeronly when the issue blocks a release.
Umbrella issues
When splitting a large piece of work into focused issues, keep the umbrella open as a tracker that links each child issue with a checkbox; close it once every child is closed or explicitly deferred.
Project management model
This repository is issue-based, not milestone-based. Track and group work using issues plus the existing label taxonomy — do not introduce parallel structures.
- Plan and group multi-issue efforts with an umbrella tracker issue (see above) plus the existing
priority:*labels. Do not create GitHub Milestones — none exist by design, and their absence is an intentional signal, not an oversight. - Do not invent new label taxonomies (e.g.
epic:*,vNext, release-tag labels) to group work. Reusepriority:*,area:*(only where they already exist), and the umbrella issue. Propose any new label in discussion and wait for explicit approval before creating it. - Treat optional or tentative suggestions ("we could…", "it might be nice to…", "~해도 괜찮아") as discussion, not a directive. Confirm intent before making any structural change to how work is tracked (milestones, labels, project boards, issue hierarchies).
- Before adding any organizational structure, check whether the repository already has an established convention. A category being empty or unused (zero milestones, no
epic:*labels) is evidence to follow the existing pattern, not to introduce a new one.
Validation
make testmake lintmake typecheckmake build
Release Process
Three tools, one job each. Nothing else participates.
| Tool | Owns |
|---|---|
| Release Please | version decision, __version__, CHANGELOG.md, Release PR, tag, GitHub Release |
| GitHub Actions | verification, real-Azure e2e, PyPI publish |
| Hatch | building the Python package (reads __version__ from src/azure_functions_knowledge/__init__.py) |
- Do NOT manually edit version strings,
CHANGELOG.md,.release-please-manifest.json, or tags. Release Please owns all of them. The public-API test reads__version__againstimportlib.metadata.version(...), so no test changes are needed when bumping. - Releases are driven by Conventional Commits on
main:fix:→ patch,feat:→ minor,feat!:/fix!:/BREAKING CHANGE:→ breaking. While this package is pre-1.0,bump-minor-pre-majorkeeps a breaking change on the0.xline. - There are no release Makefile targets.
make release-*,make changelog,make tag-release, andmake publish-pypiwere deleted; a localhatch publishwould have skipped every gate below.
Flow
feat:/fix: PR merged into main
|
Release Please -> Release PR (version + CHANGELOG)
| maintainer reviews and merges
tag vX.Y.Z + GitHub Release
|
publish-pypi.yml (started by the tag)
build -> lib-tests
-> azure-e2e -> PyPI
- Merge Conventional-Commit PRs into
main. Release Please keeps an open Release PR showing exactly what the next release would be. - Merging that Release PR is the act of cutting a release.
- Release Please tags the release commit and publishes the GitHub Release. The tag starts
publish-pypi.yml. - Every verification tier runs in that one workflow. PyPI upload happens only if all of them pass.
Certification is an in-chain gate. azure-e2e deploys to real Azure and runs the live e2e suite at the same ref being published, so it covers the exact published commit by construction. There is no separate certification step to dispatch, and no cross-run SHA or freshness matching to get wrong.
RELEASE_PLEASE_TOKEN is load-bearing. It is a fine-grained PAT stored as a repository secret. The default GITHUB_TOKEN cannot trigger other workflows, which would leave the Release PR without the required status checks — permanently unmergeable — and would stop the tag from starting publish-pypi.yml. The PAT grants repository write only; PyPI upload uses OIDC Trusted Publishing and cannot be reached with it. Fine-grained PATs expire: when it does, no Release PR appears. Regenerate it and update the secret before the expiry date.
Tiered runtime verification (what gates a release)
Every tier runs inside publish-pypi.yml on the tag, and all of them gate the upload:
| Tier | Catches |
|---|---|
build |
tag/__version__ mismatch; produces the one artifact that is later uploaded |
lib-tests |
library unit regressions (against the built wheel) |
azure-e2e |
cloud-only drift — deploys this package's own examples/e2e_app/ to real Azure (Y1 Consumption), drives the knowledge decorators' HTTP routes (/api/health, /api/search, /api/doc/{id}) against a live host, and uploads an azure-cert record keyed by commit SHA + version. |
publish |
uploads the exact artifact build produced; it never rebuilds |
Unlike the sibling repos, this package has no cookbook host-smoke tier. The real-Azure e2e deploys this package's own example app and exercises the @kb.input / @kb.inject_client decorators end-to-end, so it is the package-native runtime proof. Critically, the certification builds the candidate wheel from the release ref and bundles it into the example app (examples/e2e_app/wheels/), so Azure certifies the release commit's source — not the last-published PyPI build. The e2e also asserts that %STATIC_CONNECTION% resolved on the worker (the StaticProvider refuses to start otherwise), so a broken %VAR% substitution or provider-registration regression cannot pass.
Recovery
- Any gate failed. Nothing was uploaded, so the version is still free. Fix the cause and re-run the workflow on the same tag (
gh workflow run publish-pypi.yml --ref main -f tag=vX.Y.Z), or fix forward onmainand let the next Release PR cut a new version. Never move or reuse a tag. - A tag exists but was never published. A valid resting state. Re-run publish, or abandon the version and let the next release take the following number.
- Release PR stopped appearing. First check that
RELEASE_PLEASE_TOKENhas not expired. Then check for a staleautorelease: pendinglabel on an already-merged Release PR — Release Please treats that as a release still in flight and will not open another. This failure is silent: the workflow still reports success. - Break-glass (automation unavailable). Bump
__version__, match.release-please-manifest.json, commit, tag, and push. The tag starts the same gated workflow — never bypass it.
Golden Commands
Use Makefile entry points only. Do not bypass the Makefile in CI or contributor guidance.
| Purpose | Command |
|---|---|
| Environment setup | make install |
| Format code | make format |
Check formatting (src, tests) |
make format-check |
| Lint | make lint |
| Type check | make typecheck |
| Tests | make test |
| Coverage | make cov |
| Full validation | make check-all |
| Docs build | make docs |
| Package build | make build |
Commit Rules
Use Conventional Commits:
<type>: <short imperative summary>
Allowed types: feat, fix, refactor, docs, test, chore, ci
Agent Rules
When using AI-assisted development:
- Prefer small, reviewable changes.
- Do not guess about behavior that can be verified.
- Keep repository structure aligned with sibling repositories.
- Update docs, examples, and tests together when behavior changes.
Final Rule
If it is not automated, it will drift. If it is not documented, it is not a stable rule.
Merge Policy
mainrequires a pull request, every required status check green, and all conversations resolved. It requires zero approving reviews:yeongseonis the only account with push access and GitHub forbids approving your own PR, so a required approval could only ever be met by an administrator bypass. The required checks are what guardmain.- Never use
gh pr merge --adminto skip a failing or pending required check. - Review is still expected, just not enforced. An AI review (
COMMENTED) is not an approval. - Dependabot:
pippatch/minor updates auto-merge on green CI.github-actionsupdates never auto-merge — confirm each pinned SHA matches its claimed tag (git ls-remote --tags <repo>, compare against the dereferenced^{}commit) before merging.dependabot-automerge.ymlenforces the split. - If a second maintainer ever gets push access, raise the approval count back to 1.
Branch Hygiene
- Merged PR branches are deleted automatically ("Automatically delete head branches" is enabled on this repository); keep that setting on.
- When merging from the CLI, always pass
--delete-branch(e.g.gh pr merge --squash --delete-branch) so the head branch is removed. - Never delete
mainorgh-pages, and never delete a branch that still has an open PR. - Run
git fetch -pperiodically to prune stale local tracking refs.
