From sdlc-agents
Use this skill when working as a coder (the django-developer / the vue-developer / the react-developer) and your implementation is complete — what documentation to update, where, and how. Covers docstrings, README updates, API endpoint docs, ADR status updates, migration notes, inline comments. The author of the change is responsible for the documentation.
How this skill is triggered — by the user, by Claude, or both
Slash command
/sdlc-agents:documentation-disciplineThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
**Rule:** the author of the change owns the documentation. No one else picks it up after you. Code without documentation is incomplete — it stays in PLAN, not in CHANGES.
Rule: the author of the change owns the documentation. No one else picks it up after you. Code without documentation is incomplete — it stays in PLAN, not in CHANGES.
A common Django setup uses Sphinx with napoleon extension (<backend-app>/docs/source/conf.py). Style: Google-style docstrings (napoleon's default and most readable).
When: every non-trivial function / class / module you add OR significantly modify.
Where: in the file, immediately after the def / class line.
Google-style format:
def calculate_delivery_estimate(order, region):
"""Estimate the delivery date for an order to a region.
Combines carrier SLA (CDEK / Yandex), warehouse processing time,
and the region's holiday calendar.
Args:
order: Order instance to estimate delivery for.
region: Region instance (destination).
Returns:
datetime.date — the expected delivery date in region's local TZ,
the latest of (now + carrier SLA) and (next working day in region).
Raises:
ValueError: if region has no carrier configured.
"""
Class docstrings:
class OrderViewSet(ModelViewSet):
"""REST endpoints for customer-facing order management.
Filtered by `request.user.company` — multitenancy enforced.
Customer can list / retrieve their own orders, cancel pending ones.
Admin actions (status change, refund) are in employees.orders.
"""
Module docstring (top of models.py, services.py, etc.):
"""Customer-facing order domain.
Aggregates: Order, OrderItem, OrderHistory.
Owns the customer side of the order lifecycle (placement → cancellation).
Admin-side mutations are delegated to `employees.orders`.
"""
Skip: trivial getters / one-line setters / obvious property declarations. Comments noise = bad.
Module-level RST files: each Django app has a .rst in <backend-app>/docs/source/<app>.rst for architectural overview. When adding a new app or significantly changing one — update or create the corresponding RST.
For frontend coders (the vue-developer, the react-developer) — industry standard is TSDoc / JSDoc inline plus README.md per significant directory. We don't ship a generated docs site for each frontend (yet); inline + README is the pragmatic minimum.
/**
* Resolves the customer's tracking URL for a given order.
*
* Maps carrier code (cdek / yandex / boxberry) to the carrier's tracking page
* URL, URL-encodes the tracking_number safely.
*
* @param order - Order with tracking_number and carrier_code populated
* @returns the absolute URL to the carrier's tracking page, or null if the
* order has no tracking_number yet.
*/
export function resolveTrackingUrl(order: Order): string | null {
if (!order.tracking_number) return null
const enc = encodeURIComponent(order.tracking_number)
return CARRIER_URLS[order.carrier_code].replace('{n}', enc)
}
For Vue 3 components (<script setup>):
<script setup lang="ts">
/**
* Renders an order's status timeline as a vertical stepper.
* Skips cancelled state if order was never confirmed.
*/
const props = defineProps<{ order: Order }>()
const emit = defineEmits<{ refresh: [] }>()
</script>
For Vue 2 class components (vue-property-decorator):
<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator'
/**
* Internal employee POS view of an order.
* Allows status edits, refund initiation. Customer-side view is OrderCustomerView.
*/
@Component
export default class OrderEmployeeView extends Vue {
@Prop({ required: true }) readonly orderId!: string
}
</script>
For Angular services:
@Injectable({ providedIn: 'root' })
/**
* Caches and resolves products for the <angular-admin-app> admin views.
* Cache TTL: 60s. Invalidated on product mutation (see ProductMutationService).
*/
export class ProductCacheService { ... }
Each frontend project's significant directory (components/, composables/, stores/, pages/) gets a short README.md describing:
Example <storefront-app>/composables/README.md:
# Composables
Reusable composition functions for Vue 3 components.
## Conventions
- File name matches default export: `useOrders.ts` exports `useOrders`
- Composables prefixed with `use`
- Use `useFetch` / `useAsyncData` from Nuxt 3 for data fetching
- Pinia stores live in `stores/`, NOT here
## Files
- `useOrders.ts` — list / retrieve / cancel orders
- `useTracking.ts` — resolveTrackingUrl + carrier name display
Optional, not required by DoD. Add when the frontend has UI components reused across pages and regression risk is high. For now, inline + README is sufficient.
When: the code's "why" isn't obvious from the "what".
select_related here because the queryset is consumed once") → explainDon't: comment what the code already says. # increment counter next to counter += 1 = noise.
When: the change affects how others (developers, ops, customers) interact with the system.
.env.example and docsWhere (common conventions):
<backend-app>/docs/ directory<project>/README.md at the root of each frontend projectHow: Conventional language, examples, gotchas. Assume reader is a smart developer new to the project.
When you implement a feature with an Accepted ADR (from SPEC §6):
Implemented in the SPEC sub-issue (post a short comment, don't edit description).When your change includes a migration:
Both qsale (qa-server) and coinex (coinex-server) use drf-spectacular to generate OpenAPI schema → ReDoc / Swagger UI. The schema is built from the view's source code: by default, the view's docstring becomes the operation description in the published API docs. No docstring → empty docs in production.
For every new / modified API endpoint, do all of this — these are measurable requirements, not formalities:
View class has a docstring, single-line summary on the first line + structured body. drf-spectacular splits the first line as summary and the rest as description. Example:
class OrderTrackingView(APIView):
"""Return tracking info for a customer's order.
Path: GET /api/v1/orders/{id}/tracking/
Returns: 200 with {tracking_number, carrier, last_event}
404 if the order does not belong to the authenticated tenant
Errors: 401 unauthenticated, 403 wrong role
"""
Override only when the docstring is not enough — use @extend_schema(...) on the view method (get, post, etc.) to add precise request/response schemas, status codes, examples. Keep the docstring as the human-readable description; let @extend_schema carry the structured contract.
Run the project's OpenAPI verifier as part of CHANGES verification. The exact command is project-specific and lives in $KB_DIR/kb/verify.md — typically a slash-command like /verify-openapi wrapping a make.sh openapi-check target that runs python manage.py spectacular --validate --fail-on-warn … under the hood. Do NOT inline raw manage.py commands in your CHANGES — call the project's wrapper so behaviour stays consistent across runs and projects. The wrapper must:
spectacular --validate --fail-on-warn (or equivalent) to make missing-description / missing-help_text warnings fatal,The CHANGES verification field MUST include this command and its result (e.g. ✅ /verify-openapi — 0 warnings, 0 errors). post_changes(ready_for_review=True) (plane-api.md §6.7d) refuses without it.
If the project does not yet expose this verifier in kb/verify.md, that's a project-side gap — surface it via escalate_upstream_gap (plane-api.md §6.7c) before claiming ready_for_review=True.
Help text on serializer fields — every non-trivial Serializer field should pass help_text="...". drf-spectacular pulls it into the schema's field description; without it, ReDoc shows naked field names.
For non-standard endpoints (idempotency keys, custom headers, file upload, async polling) — document in the view docstring AND mirror in @extend_schema(parameters=[...]) so they appear in the published docs.
Test function names ARE documentation:
test_order_1, test_createtest_create_order_returns_201_with_order_uuidtest_cancel_already_cancelled_order_returns_409_conflictA reader of the test suite should understand the API behaviour from test names alone.
def get_id(): return self.id doesn't need a docstring).| Documentation type | Location |
|---|---|
| Python docstrings | inline in code |
| API endpoint behaviour | view class docstrings + drf-spectacular schemas |
| Backend developer guide | <backend-app>/docs/ directory |
| Frontend project README | <project>/README.md (, , , ) |
| Architecture decisions | SPEC sub-issue ADRs in Plane (long-lived) |
| Operational runbooks | helm-values, helm-charts repos |
| User-facing features | external help center (the business-analyst's domain, not coder's) |
A coder's CHANGES is incomplete unless:
.env.example updatedThis goes in the final step of Phase 2, alongside /run-tests-all etc. Don't mark step [x] until docs are also updated.
npx claudepluginhub volodchenkov/claude-sdlc-agents --plugin sdlc-agentsGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.