Repository Guidelines
Instruction Files
Read these before making changes; they are authoritative for repo workflows.
| Topic | File |
|---|---|
| Agent instructions | .github/copilot-instructions.md |
| Documentation | docs/index.md |
Project Structure
linkml/contains LinkML schema definitions for credential typesartifacts/contains generated OWL, SHACL, and JSON-LD context filesexamples/contains example credential instances for testingmanifests/contains wallet rendering manifestssrc/contains Python source code for the credentials pipelinedocs/contains MkDocs source pagestests/contains pytest testssubmodules/contains git submodules:harbour-credentials— cryptographic signing/verification libraryharbour-credentials/submodules/ontology-management-base— ontology validation pipelineharbour-credentials/submodules/w3id.org— W3ID redirect rules
Build, Test, and Development Commands
Always use make targets — never call generators, linters, or test runners
directly. Each repository in the submodule chain has its own Makefile with a
consistent command surface. Run make help to discover available targets.
# Install dev dependencies
make setup
make install dev
# Generate artifacts from LinkML schemas
make generate # all domains
make generate DOMAIN=<name> # single domain (OMB)
make generate gx # Gaia-X from service-characteristics (OMB)
# Lint and format
make lint
make format
# Run tests
make test
# Run validation pipeline
make validate
The make targets handle virtualenv activation, correct flags, line-ending
normalisation, and cross-platform path issues. Bypassing them (e.g. calling
gen-owl or python -m directly) risks producing artifacts with wrong
line endings, missing flags, or inconsistent output.
Git Commit & Pull Request Policy
Commit Requirements
- Always sign commits with
-s -Sflags (Signed-off-by + GPG signature) - Never include AI attribution in commits — no
Co-Authored-By,Generated-By, or similar headers mentioning AI assistants (Claude, Copilot, ChatGPT, etc.) - Never mention AI tools in commit messages — do not reference that code was AI-generated or AI-assisted
- Author must be a human developer with their official email address
- Use conventional commit format:
feat:,fix:,docs:,chore:,refactor:,test:
# Correct commit command
git commit -s -S -m "feat: add new credential type"
Preparing Commits and Pull Requests
When instructed to prepare a commit or PR, default to preparing the .playground
files first. After explicit human confirmation in the current session, the
agent may directly create the signed commit, push the branch, and open the PR
using the prepared .playground content. Otherwise:
- Create the
.playground/directory (already in.gitignore) - Generate two markdown files:
.playground/commit-message.md— Conventional commit message(s).playground/pr-description.md— PR description following the repository's PR template
The human operator will review these files and either:
- Use them to manually commit/push and create a PR,
- Ask the agent to perform the signed commit/push/PR flow directly after explicit confirmation, or
- Use automated tooling with signed commits (
git commit -s -S)
Commit Message Format
# .playground/commit-message.md
feat(linkml): add MembershipCredential schema
- Define membership credential with role claims
- Add selective disclosure annotations
- Include example instance
Refs: #123
PR Description Format
Follow .github/pull_request_template.md if it exists, otherwise use:
# .playground/pr-description.md
## Summary
Brief description of the changes.
## Changes
- List of specific changes made
- Another change
## Testing
- [ ] Tests pass locally (`make test`)
- [ ] Validation passes (`make validate`)
## Related Issues
Closes #123
Verification Before Push
STRICT REQUIREMENT — never push without local verification.
Before pushing any branch or accepting a solution as complete, the agent must:
-
Run tests locally (
make test) in the affected repository and confirm they pass -
Run validation locally (
make validate) when schemas or artifacts changed -
Run lint locally (
make lint) to catch formatting issues -
Regenerate artifacts (
make generate) when LinkML schemas changed, and verify the generated output is as expected -
Run GitLab CI locally when changing
.gitlab-ci.ymlor CI-related files inservice-characteristics:# Requires: npm install -g gitlab-ci-local # Requires: rsync (via msys2: pacman -S rsync, or apt: apt install rsync) # Requires: Docker/Podman for container-based jobs gitlab-ci-local # run all jobs gitlab-ci-local --job test-shacl # run a single job gitlab-ci-local --list # list available jobsNote: On corporate networks, Docker image pulls may require proxy configuration. If
gitlab-ci-localcannot pull images, verify the CI changes are correct by inspection and note the limitation in the PR. -
Check submodule CI — after pushing a submodule branch, observe the CI pipeline (GitHub Actions / GitLab CI) and wait for it to go green before cascading pins to the next layer. Do not assume CI will pass; check it.
For the multi-layer submodule chain (service-characteristics → OMB → harbour-credentials → credentials), this means:
- Fix and test at the innermost affected layer first
- Push that layer, observe its CI, confirm green
- Only then update the submodule pin in the next layer up
- Repeat until all layers are green
Never skip local testing with the assumption that CI will catch issues. CI is a safety net, not a substitute for local verification.
Standards Compliance
STRICT REQUIREMENT — all schemas, examples, and models must align with the relevant W3C, IETF, and industry specifications.
When defining or modifying LinkML schemas, JSON-LD examples, or DID documents:
-
Cross-reference the spec copy in
docs/. The LinkML schema files use bracketed tags (e.g.[VCDM2],[DID Core],[OID4VP],[SD-JWT]) that cite specific spec sections. Before changing a slot range, class hierarchy, or property definition, locate the corresponding spec document indocs/and verify the modeling choice against the normative text. -
Document the rationale in the schema. Every non-trivial modeling decision must have a YAML comment citing the spec section and briefly explaining why the chosen type/range/constraint is correct. Example:
# [DID Core] §5.4 — serviceEndpoint is a URI, map, or set thereof. # Base range is uri (the common case); service-specific classes # override via slot_usage for structured endpoint objects. serviceEndpoint: slot_uri: didcore:serviceEndpoint range: uri -
Use standard vocabulary (DID Core, VC Data Model 2.0, OID4VP, schema.org, Gaia-X Trust Framework) rather than inventing new terms.
-
Never use
range: Anyin LinkML slot definitions.linkml:Anyproducesrdfs:range linkml:Anyin OWL, which triggers closed-shape SHACL violations during RDFS inference. Always choose a spec-aligned range:urifor properties whose values are network addresses or identifiers (e.g. DID CoreserviceEndpoint)- A named class for structured objects with a defined schema
(e.g. OID4VP
TransactionData)
-
Validate examples against SHACL (
make validate) to catch inference issues before they reach CI.
| Spec area | Key reference |
|---|---|
| DID documents | W3C DID Core 1.1 (docs/) |
| Credentials | W3C VC Data Model 2.0 (docs/) |
| Delegated signing | OID4VP 1.0 §8.4 (docs/) |
| Gaia-X compliance | Gaia-X Trust Framework (docs/) |
| Schema vocabulary | schema.org (imports/schema/) |
Coding Style
- Python 3.12+ with type hints
- Use
pathlib.Path(notos.path) - 4-space indentation
- Module docstrings required
- Run
make lintbefore committing