Package/Folder Documentation Guidelines
Guidelines for writing comprehensive module documentation, derived from timezoned.md, observable.md, and
reflection.md.
---
Workspace Metadata
Before working on documentation, consult the .tom_metadata/index.yaml file at the workspace root to understand: - Project structure (projects, parts, modules) - Correct naming and hierarchy - Module relationships
See project_structure.md for details on the metadata format.
---
User Documentation Location
1. Documentation Folder Structure
-
User documentation should always be placed in a
doc/folder, normally at project level - If a project has parts and/or modules, documents should be in subfolders accordingly
- Example structure for a project with modules:
project/
doc/
user_guide.md
architecture.md
api/
api_summary_{module_a}.md
api_summary_{module_b}.md
{module a}/
{module a}.md
{module b}/
{module b}.md
- Example structure for a project with modules:
project/
doc/
{project}_user_guide.md
{project}_architecture.md
api/
api_summary_{module_a}.md
api_summary_{module_b}.md
{part1}/
{part1}.md
{module a}/
{module a}.md
{module b}/
{module b}.md
{part2}/
{part2}.md
{module c}/
{module c}.md
{module d}/
{module d}.md
2. PDF Files
- Some documentation may be in
.pdfformat (read-only) - PDFs should also be placed in the
doc/folder
3. README.md Files
-
README.mdfiles should always remain where they are (project root, folder root, etc.) - Never move README.md files to doc/
README.md Structure
Every package README.md should include:
1. Title and Badge - Package name, pub.dev version badge 2. Description
- One paragraph explaining what the package does 3. Features - Bulleted list of key capabilities 4.
Installation - pubspec.yaml dependency snippet 5. Quick Start
- Minimal working example 6. Basic Usage - Common usage patterns 7. Documentation Links
- Links to detailed guides 8. License - License type (usually MIT)
Example Template:
# Package Name
Brief one-paragraph description of what this package does.
## Features
- Feature 1
- Feature 2
- Feature 3
## Installation
Add to your `pubspec.yaml`:
dependencies: package_name: ^1.0.0
## Quick Start
import 'package:package_name/package_name.dart';
void main() { // Minimal example }
## Documentation
- [User Guide](doc/user_guide.md)
- [API Reference](doc/api/)
## License
MIT License
4. CHANGELOG.md Files
Every package should have a CHANGELOG.md at the root following Keep a Changelog
format.
CHANGELOG Structure
# Changelog
All notable changes to this project will be documented in this file.
## [Unreleased]
### Added
- New features being developed
## [1.2.0] - 2024-01-15
### Added
- New feature X that does Y
### Changed
- Modified behavior of Z
### Deprecated
- Feature A will be removed in v2.0
### Fixed
- Bug where X happened under Y conditions
### Removed
- Removed deprecated feature B
### Security
- Fixed vulnerability in X
## [1.1.0] - 2024-01-01
...
CHANGELOG Guidelines
- Keep entries concise - One line per change
- Use present tense - "Add feature" not "Added feature"
- Group by type - Added, Changed, Deprecated, Fixed, Removed, Security
- Most recent first - Newest version at the top
- Include dates - ISO format (YYYY-MM-DD)
- Link to issues - Reference issue numbers where applicable
5. Project-Specific Guidelines
Some projects have their own _copilot_guidelines/ folder with project-specific documentation rules.
Always check for project-level guidelines: 1. Look for {project}/_copilot_guidelines/
folder 2. Check index.md for available documentation 3. Follow project-specific rules over global rules when they conflict
Creating Project Guidelines: When creating a new _copilot_guidelines/ folder for a project, include: -
index.md - Index of available guidelines - example.md - Example file creation guidelines -
documentation.md - Project-specific documentation rules - build.md - Build, test, and publishing guidelines
6. Module Documentation
- Module-level technical documentation (API docs) may remain alongside source code
- User-facing documentation goes to
doc/
7. API Documentation
-
For creating
api_summary_{module}.mdfiles, see api_summary_creation.md - For creating combined API reference PDFs, see api_reference_creation.md
-
For creating
api.dartbarrel files that export the public API, see api_guide.md
---
File Naming and Location
1. File Naming
- Name the documentation file after the folder/module:
{module_name}.md - Place it in the same folder as the source files it documents
- Examples:
lib/src/tombase/timezoned/timezoned.mdlib/src/tombase/observable/observable.mdlib/src/tombase/reflection/reflection.md
2. One File Per Module
Each module folder should have exactly one main documentation file that covers all classes and concepts in that module.
---
Document Structure
Required Sections (in order)
Every module documentation file must include these sections:
# Tom {Module Name} System
{One-paragraph summary of what the module does}
## Table of Contents
- [Overview](#overview)
- [Quick Start](#quick-start)
- [Core Components](#core-components)
- ... {feature-specific sections}
- [Error Handling](#error-handling)
- [Best Practices](#best-practices)
## Overview
{Detailed explanation of the module}
## Quick Start
{Minimal working examples}
## Core Components
{Main classes and their roles}
## {Feature Sections}
{Deep dives into each feature}
## Error Handling
{Common errors and solutions}
## Best Practices
{Usage recommendations}
Optional Sections (as needed)
## Dependencies- External packages or other modules required## Build Configuration- For modules requiring code generation## Class Hierarchy- For complex inheritance structures## Serialization- For modules with custom serialization formats
---
Section Guidelines
1. Title
# Tom {Module Name} System
- Always prefix with "Tom"
- Use "System" suffix for modules
- One sentence summary immediately follows:
# Tom Timezoned System
The Tom Timezoned System provides robust timezone-aware date and time handling for Dart applications.
It extends Dart's built-in `DateTime` with proper timezone support, serialization, and
automatic handling of daylight saving time (DST) transitions.
2. Table of Contents
- Use markdown links to section anchors
- Include all major sections
- Nest sub-sections with indentation for complex modules:
## Table of Contents
- [Overview](#overview)
- [Quick Start](#quick-start)
- [Core Components](#core-components)
- [TomObservable](#tomobservable)
- [TomObserver](#tomobserver)
- [TomFunctionObserver](#tomfunctionobserver)
- [Observable Primitives](#observable-primitives)
- [Non-Nullable Types](#non-nullable-types)
- [Nullable Types](#nullable-types)
3. Overview
The overview section must include:
a) Component List
Describe the main files/classes and their responsibilities:
## Overview
The timezoned system consists of two main components:
1. **`TomTimezone`**: A wrapper around the `timezone` package's `Location` class that provides
timezone lookup, UTC offset calculation, and formatting.
2. **`TomTimezoned`** and subclasses: DateTime extensions that store values as **true UTC internally**
while maintaining the associated timezone for display and conversion.
The type table, and why it is exhaustive
A module document whose Overview opens with a table of the module's types undertakes to list every public type the package barrel reaches from that module — not a selection:
## Overview
| Type | Kind | Purpose |
| ---- | ---- | ------- |
| `TomUserPreference` | class | The `tom_user_preference` row; carries the row scope |
| `TomUserPreferenceRepository` | class | Persists that entity |
A curated list cannot be checked, and that is not an abstract objection. tom_core_server's preferences document named five of its six public types, and the missing one was the subject of the document's own longest section. It went unnoticed for months because, with no rule about what belongs, an omission contradicts nothing.
Exhaustive costs something, and the cost is accepted. A module with eighty-five public types gets an eighty-five-row table, most rows one line. Such a table is closer to an index than an overview — but an index that is complete beats an overview that is silently partial, because a reader takes the silence of a list for an answer.
Presentation stays free. A row may cover names that are used as a set — ` TomSelect /
TomCount / TomDelete on one row — and a family may share a row provided every member is named on it. What is not allowed is an ellipsis:
TomButtonBase, TomInputBase, … ` is where a type goes missing without contradicting anything, which is the defect this rule exists for.
The table is what puts the document in scope. An Overview written as prose is a different shape and this rule does not reach it; a table with a
Type (or Symbol) column beside a Kind column is the document declaring that this region enumerates its module. In the Tom workspace,
tom_ai/core/tool/check_doc_overview_types.py enforces it for the packages that write one.
b) Internal Model (if applicable)
Explain non-obvious internal design decisions:
### Internal Storage Model
All `TomTimezoned` values store the actual UTC moment internally:
- **Standard accessors** (`year`, `month`, `day`, `hour`, etc.) return **UTC values**
- **Local accessors** (`localYear`, `localMonth`, `localDay`, `localHour`, etc.) return **local time values**
c) Value Proposition
A bulleted list of why users should use this module:
### Why Use TomTimezoned?
- **Timezone preservation**: Unlike `DateTime`, timezone context is preserved across operations
- **Automatic DST handling**: UTC offsets are calculated correctly for any point in time
- **Serialization**: Built-in string format preserves both the datetime and timezone information
- **Type safety**: Separate classes for date-only, time-only, and full datetime values
- **IANA timezone names**: Uses standard identifiers like `'America/New_York'` or `'Asia/Tokyo'`
4. Quick Start
Provide the absolute minimum code to get started. Structure as numbered steps:
## Quick Start
### 1. Annotate Your Class
import 'package:tom_core/tom_core.dart';
@tomReflector class Person { String name = ''; int age = 0; }
### 2. Initialize Reflectable
import 'my_file.reflectable.dart';
void main() { initializeReflectable(); }
### 3. Use Reflection
final person = tomReflectionInfo.createInstance<Person>(); tomReflectionInfo.setValues(person, {'name': 'John', 'age': 30});
Quick Start Requirements: - Maximum 3-5 steps - Each step has a clear heading - Code examples are complete and runnable - Include imports - Show the most common use case
5. Core Components
For each main class, provide:
## Core Components
### TomReflector
The `TomReflector` class extends `Reflectable` and is configured with the necessary
capabilities for reflection operations:
class TomReflector extends Reflectable { const TomReflector() : super.fromList(const [ invokingCapability, typingCapability, // ... ]); }
### TomReflectionInfo
The main class for reflection operations. Key methods:
| Method | Description |
|--------|-------------|
| `createInstance<T>()` | Create a new instance using default constructor |
| `setValues<T>(object, values)` | Set field values on an existing object |
| `getValues(object)` | Get all field values as a map |
Component Documentation Pattern: 1. One-sentence description 2. Brief explanation paragraph 3. Code example showing structure OR method table 4. Link to detailed section if complex
6. Feature Sections
Each major feature gets its own section with:
## TomZonedDateTime
Full date and time values. **Serialization prefix**: `@X@`
final tokyo = TomTimezone.fromName('Asia/Tokyo')!;
// Create with components final dt = TomZonedDateTime( year: 2024, month: 6, day: 15, hour: 14, minute: 30, timezone: tokyo, );
// Create from DateTime final now = TomZonedDateTime.fromDateTime(DateTime.now(), tokyo);
// Parse from string final parsed = TomZonedDateTime.parseFromString( '@X@2024-06-15T05:30:00.000Z_+09:00_Asia/Tokyo' );
// Check string format if (TomZonedDateTime.isTomZonedDateTimeString(input)) { ... }
Feature Section Pattern: 1. One-line description with key metadata (e.g., serialization prefix) 2. Code examples showing all common operations: - Creation (multiple ways) - Parsing - Validation - Key methods
7. Tables for Reference
Use tables for quick-reference information:
Method Tables
| Method | Description |
|--------|-------------|
| `createInstance<T>()` | Create a new instance using default constructor |
| `setValues<T>(object, values)` | Set field values on an existing object |
Type Tables
| Class | Wraps | Default Value |
|-------|-------|---------------|
| `TomString` | `String` | `""` |
| `TomInt` | `int` | `0` |
| `TomDouble` | `double` | `0.0` |
Operator Tables
| Operator | Usage | Description |
|----------|-------|-------------|
| `~` | `~observable` | Get the current value |
| `\|` | `observable \| value` | Set the value and notify |
| `>>` | `observable >> callback` | Add an observer callback |
Error Key Tables
| Error Key | Description |
|-----------|-------------|
| `reflector.instance_creation.failed` | Failed to create instance |
| `reflection.set.unexpected_type` | Unexpected value type during deserialization |
8. Error Handling Section
Structure:
## Error Handling
### TomTimezoneException
Thrown when timezone validation fails:
try { TomTimezone.findTimezone('America/New_York', 540); // +9:00 doesn't match NY } on TomTimezoneException catch (e) { print(e.defaultUserMessage); }
### Null Returns
Lookup methods return `null` for unknown values:
final tz = TomTimezone.fromName('Invalid/Zone'); // null final offset = TomTimezone.firstWithOffset(99999); // null
### Format Exceptions
Thrown when parsing fails:
try { TomZonedDateTime.parseFromString('invalid'); } on FormatException catch (e) { print(e.message); }
### Common Error Keys
| Error Key | Description |
|-----------|-------------|
| `timezone.not_found.name_offset_mismatch` | Name and offset don't match |
Required elements: 1. Each exception type with example 2. Table of common error keys 3. Safe pattern for handling (try-catch example)
9. Best Practices Section
Structure as actionable headings with code examples:
## Best Practices
### Use Local Accessors for Display
// Display: use local accessors print('${meeting.localHour}:${meeting.localMinute}'); // 14:30 (Tokyo time)
// Internal: UTC values print('${meeting.hour}:${meeting.minute}'); // 05:30 (UTC)
### Preserve Timezone in Serialization
// Good - preserves timezone final json = {'meeting_time': meeting.toString()};
// Avoid - loses timezone final json = {'meeting_time': meeting.toIso8601String()};
### Validate Before Parsing
if (TomZonedDateTime.isTomZonedDateTimeString(input)) { final dt = TomZonedDateTime.parseFromString(input); } else { // Handle invalid input }
Best Practice Pattern: 1. Action-oriented heading (verb phrase) 2. Brief explanation (optional) 3. Code example showing the recommended approach 4. Counter-example showing what to avoid (when helpful)
10. Class Hierarchy Section (if applicable)
Use ASCII tree diagrams:
## Class Hierarchy
TomObservable (base class) └── TomObject<T> ├── TomString, TomInt, TomDouble, TomBool, TomDateTime ├── TomNString, TomNInt, TomNDouble, TomNBool, TomNDateTime ├── TomOTimezoned<TZ> │ ├── TomOZonedTime, TomOZonedDate, TomOZonedDateTime │ └── TomNOTimezoned<TZ> │ └── TomNOZonedTime, TomNOZonedDate, TomNOZonedDateTime ├── TomClass (also implements TomObserver) │ └── TomDateRange, TomTimeRange, TomDateTimeRange ├── TomList<E> (also implements TomObserver, Iterable) └── TomMap<K, V> (also implements TomObserver)
11. Dependencies Section (if applicable)
## Dependencies
The observable system depends on:
- **`reflection.dart`**: `@tomReflector` annotation for `TomClass` reflection
- **`date_timestamp.dart`**: `TomZonedDate`, `TomZonedTime`, `TomZonedDateTime`
- **`tom_exception.dart`**: Base `TomException` class
### Required Import
import 'package:tom_core/tom_core.dart';
---
Code Example Standards
1. Complete and Runnable
Every code example should be complete enough to copy-paste and run:
// Good - includes import and context
import 'package:tom_core/tom_core.dart';
void main() {
final tokyo = TomTimezone.fromName('Asia/Tokyo')!;
final meeting = TomZonedDateTime(
year: 2024, month: 6, day: 15, hour: 14,
timezone: tokyo,
);
print(meeting.localHour); // 14
}
// Bad - missing context
final meeting = TomZonedDateTime(...); // Where does this go?
2. Show Expected Output
Include comments showing expected results:
print(~name); // "Jane"
print(meeting.localHour); // 14 (local time in Tokyo)
print(meeting.hour); // 5 (UTC time)
3. Use Realistic Values
Use meaningful, realistic data in examples:
// Good - realistic data
final meeting = TomZonedDateTime(
year: 2024, month: 6, day: 15, hour: 14, minute: 30,
timezone: TomTimezone.fromName('Asia/Tokyo')!,
);
// Avoid - generic placeholder data
final meeting = TomZonedDateTime(year: 1, month: 1, day: 1, hour: 0);
4. Use Deterministic Values
Avoid DateTime.now() in examples - use fixed dates:
// Good - deterministic
final winter = DateTime.utc(2024, 1, 15);
final summer = DateTime.utc(2024, 7, 15);
// Avoid - non-deterministic
final now = DateTime.now(); // Different every time
5. Group Related Examples
When showing multiple creation methods, group them together:
// Create with components
final dt = TomZonedDateTime(year: 2024, month: 6, day: 15, timezone: tokyo);
// Create from DateTime
final now = TomZonedDateTime.fromDateTime(DateTime.now(), tokyo);
// Parse from string
final parsed = TomZonedDateTime.parseFromString('...');
---
Formatting Standards
1. Headings
#- Document title only (one per file)##- Major sections###- Subsections####- Sub-subsections (use sparingly)
2. Emphasis
-
Bold for class names in prose: "The
TomReflectorclass..." Backticksfor inline code: "Use the>>operator..."- Italics for emphasis on concepts (rare)
3. Lists
Use unordered lists for features/options:
- **Timezone preservation**: Unlike `DateTime`, timezone context is preserved
- **Automatic DST handling**: UTC offsets are calculated correctly
- **Serialization**: Built-in string format preserves datetime and timezone
Use ordered lists for sequential steps:
1. Annotate your class with `@tomReflector`
2. Run `dart run build_runner build`
3. Import the generated `.reflectable.dart` file
4. Call `initializeReflectable()` in your main function
4. Code Blocks
Always specify the language:
// Dart code here
YAML configuration here
Shell commands here
5. Fenced Code for Serialization Formats
Use plain code blocks for showing format patterns:
{PREFIX}ISO8601_UTC_OFFSET_TIMEZONE
---
Length Guidelines
| Section | Target Length | Maximum |
|---|---|---|
| Title + Summary | 2-4 lines | 5 lines |
| Table of Contents | Match sections | N/A |
| Overview | 150-300 words | 400 words |
| Quick Start | 3-5 steps | 7 steps |
| Core Components | 50-100 words per class | 150 words |
| Feature Sections | 100-200 words + code | 300 words |
| Error Handling | 100-200 words | 300 words |
| Best Practices | 5-10 practices | 15 practices |
Total document length: - Small modules: 300-500 lines - Medium modules: 500-800 lines - Large modules: 800-1100 lines
---
Checklist for New Documentation
- [ ] File named
{module_name}.mdin module folder - [ ] Title follows "Tom {Name} System" pattern
- [ ] One-paragraph summary immediately after title
- [ ] Table of Contents with all sections linked
- [ ] Overview explains components and value proposition
- [ ] Quick Start has 3-5 numbered steps with complete code
- [ ] Core Components section covers all main classes
- [ ] Feature sections have code examples for all operations
- [ ] Tables used for methods, types, operators, errors
- [ ] Error Handling covers all exception types
- [ ] Best Practices has 5+ actionable recommendations
- [ ] All code examples are complete and show expected output
- [ ] No
DateTime.now()or non-deterministic values in examples - [ ] Imports included in code examples where needed
- [ ] Consistent heading hierarchy (no skipped levels)
- [ ] Markdown code blocks specify language
---
Maintenance Guidelines
When to Update Documentation
1. New public API - Add to relevant section 2. Breaking changes - Update examples and add migration notes 3. New best practices discovered - Add to Best Practices 4. Common user errors identified - Add to Error Handling 5. New use cases - Add examples to relevant sections
Documentation Review Checklist
- [ ] All public classes/methods documented
- [ ] Examples still compile and run
- [ ] Output comments match actual output
- [ ] Links in Table of Contents work
- [ ] No outdated API references
- [ ] Consistent with actual code behavior