Agent skill
synnovator
Manage Synnovator platform data: 7 content types (category, post, resource, rule, user, group, interaction) and 9 relationship types via a file-based YAML+Markdown engine. Data stored in PROJECT_DIR/.synnovator/. Use when performing CRUD operations on platform content, managing activities/competitions, teams, posts, user interactions (likes/comments/ratings), or testing user journeys. Trigger: any request involving Synnovator platform data, user journey simulation, or content management.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/synnovator
SKILL.md
Synnovator
File-based data engine for the Synnovator platform. All records are .md files with YAML frontmatter + Markdown body, stored under PROJECT_DIR/.synnovator/.
Quick Start
# Initialize data directory
uv run python .claude/skills/synnovator/scripts/engine.py --init
# CRUD operations
uv run python .claude/skills/synnovator/scripts/engine.py [--user USER_ID] COMMAND TYPE [OPTIONS]
Commands: create, read, update, delete
Data Model
7 content types stored as .md files in .synnovator/<type>/:
category- Activities/competitions (YAML + Markdown body)post- User posts with tags (YAML + Markdown body)resource- File attachments (YAML frontmatter only)rule- Activity rules with scoring criteria (YAML + Markdown body)user- User accounts (YAML frontmatter only)group- Teams/groups (YAML frontmatter only)interaction- Likes, comments, ratings (YAML frontmatter only). Target info is stored intarget_interactionrelation, not on the interaction itself.
9 relationship types stored in .synnovator/relations/<type>/:
category_rule- Activity-to-rule bindingscategory_post- Activity-to-post submissionscategory_group- Team activity registrationcategory_category- Activity association (stage / track / prerequisite)post_post- Post references/embeds/repliespost_resource- Post-to-attachment linksgroup_user- Group membership (with approval workflow)user_user- User follow/block relationshipstarget_interaction- Content-to-interaction bindings
See references/schema.md for complete field definitions.
Content CRUD
Create
engine.py [--user UID] create <type> --data '<json>' [--body 'markdown content']
Auto-generates: id, created_at, updated_at, deleted_at. Sets created_by from --user.
Read
engine.py read <type> --id <record_id> # Single record
engine.py read <type> --filters '<json>' # Filtered list
engine.py read <type> --include-deleted # Include soft-deleted
Update
engine.py update <type> --id <record_id> --data '<json>'
For tags: "+tagname" appends, "-tagname" removes. Body: "_body": "new markdown".
Delete
engine.py delete <type> --id <record_id> # Soft delete (default)
engine.py delete <type> --id <record_id> --hard # Hard delete
Cascades: deleting a post removes its relations and soft-deletes linked interactions.
Relation CRUD
engine.py create <rel_type> --data '<json>' # Create
engine.py read <rel_type> --filters '<json>' # Read
engine.py update <rel_type> --filters '<json>' --data '<json>' # Update
engine.py delete <rel_type> --filters '<json>' # Delete (hard)
Use _ or : separator: category_rule or category:rule.
Key Behaviors
- Soft delete: Sets
deleted_at, record stays on disk. Default for content types. - Hard delete: Removes file. Default for relations.
- Cache stats:
like_count,comment_count,average_ratingon posts are read-only — auto-recalculated whentarget_interactionrelations are created/deleted. Manual updates to these fields are silently ignored. - Two-step interactions: Creating an interaction requires: (1)
create interactionfor the record, (2)create target_interactionto link it to a target. Cache updates, duplicate-like checks, and target validation happen at step 2. - Group approval:
require_approval=truesets join status topending; owner approves viaUPDATE group_user. - Uniqueness: Enforced for user
(username),(email); like(user, target)attarget_interactioncreation; relation duplicates; user-per-category-per-group (a user can only belong to one group per category);user_user(source_user_id, target_user_id, relation_type);category_category(source_category_id, target_category_id). - Self-reference prevention:
user_userandcategory_categorycannot reference the same entity as both source and target. - Block enforcement: If user B blocks user A, A cannot follow B.
- Circular dependency detection:
category_categorywithstageorprerequisiterelation types prevents cycles (A→B→C→A). - Prerequisite enforcement: Creating a
category_groupregistration checks that all prerequisite categories (viacategory_categoryprerequisite) are closed. - Cascades: Deleting content cascades to relations and interactions per the schema spec. Notably:
- Deleting a group cascades to both
group_userandcategory_grouprelations. - Deleting a user cascades to
group_useranduser_userrelations and soft-deletes all user interactions. - Deleting a category cascades to
category_rule,category_post,category_group, andcategory_categoryrelations and soft-deletes linked interactions.
- Deleting a group cascades to both
Rule Enforcement
Rules linked to a category via category_rule are automatically enforced via a hook system. Rules support two definition styles: fixed fields (backward-compatible shorthand) and declarative checks (extensible condition-action pairs). All rules must pass (AND logic); any single violation rejects the operation.
Hook Points
| Operation | Phase | Validations |
|---|---|---|
create category_post |
pre | Time window, max submissions, submission format, min team size, resource requirements, entry prerequisites |
create category_post |
post | Post-submission actions (notifications, etc.) |
create group_user |
pre | Max team size (checked against all categories the group is registered for) |
create group_user |
post | Post-join actions |
create category_group |
pre | Prerequisite categories closed, entry conditions (team/proposal existence) |
create category_group |
post | Post-registration actions |
update post.status |
pre | allow_public / require_review path enforcement |
update post.status |
post | Post-status-change actions |
update category.status |
pre | Pre-closure validation |
update category.status |
post | Closure actions: disqualification flagging, ranking computation, certificate awarding |
Phases
- pre: Runs before the operation.
on_fail: denyblocks the operation.on_fail: warnallows with warning.on_fail: flagmarks but allows. - post: Runs after a successful operation. Never blocks. Used for compute/award/notify actions.
Validation Chain
category_post: category → category_rule → rule.checks[trigger=create_relation(category_post)]
group_user: group → category_group → category → category_rule → rule.checks[trigger=create_relation(group_user)]
category_group: category → category_category(prerequisite) + category_rule → rule.checks[trigger=create_relation(category_group)]
post.status: post → category_post → category → category_rule → rule.checks[trigger=update_content(post.status)]
category.status: category → category_rule → rule.checks[trigger=update_content(category.status)]
Fixed Fields as Syntactic Sugar
Fixed fields on Rule (max_submissions, min_team_size, submission_format, etc.) are automatically expanded into equivalent checks entries by the engine. User-defined checks are appended after expanded entries.
| Fixed Field | Expands To |
|---|---|
submission_start / submission_deadline |
time_window check on create_relation(category_post) pre |
max_submissions |
count check on create_relation(category_post) pre |
submission_format |
resource_format check on create_relation(category_post) pre |
min_team_size |
count check on create_relation(category_post) pre |
max_team_size |
count check on create_relation(group_user) pre |
allow_public / require_review |
field_match check on update_content(post.status) pre |
Condition Types
| Type | Description |
|---|---|
time_window |
Current time within [start, end] |
count |
Entity/relation count satisfies op + value |
exists |
Entity/relation exists (or must not exist) |
field_match |
Entity field matches a predicate |
resource_format |
Post resources match allowed formats |
resource_required |
Post has minimum required resources |
unique_per_scope |
Uniqueness within a scope |
aggregate |
Aggregated value (count/sum/avg) meets threshold |
Action Types (post phase only)
| Action | Description |
|---|---|
flag_disqualified |
Mark entities that fail post-closure checks |
compute_ranking |
Calculate rankings from average_rating |
award_certificate |
Auto-create certificate resources and posts per rank range |
notify |
Send notifications (reserved, not yet implemented) |
Behavior
- No rules linked → no constraints, operation proceeds normally.
- Rule field absent → that constraint is skipped (e.g., no
submission_deadlinemeans no time limit). - Violation (pre) → operation rejected with error:
Rule '<name>': <reason>. - Violation (post) → action executes (flag/compute/award), does not rollback.
- Posts not linked to any category are unconstrained (rules only apply through
category_post).
See docs/rule-engine.md for the full specification.
File Format
Each record is a .md file:
---
name: 2025 AI Hackathon
type: competition
status: published
id: cat_abc123
created_by: user_alice
created_at: '2025-01-01T00:00:00Z'
---
## Activity Description
Markdown content here.
Testing
Tests are organized as modular files under scripts/tests/, one per test-case spec in specs/testcases/.
# Run all tests
uv run python .claude/skills/synnovator/scripts/tests/run_all.py
# Run specific test files by number
uv run python .claude/skills/synnovator/scripts/tests/run_all.py 3 4 11
# Run a single test file directly
uv run python .claude/skills/synnovator/scripts/tests/test_11_user_journeys.py
Test File Map
| # | File | TC Prefix | Coverage |
|---|---|---|---|
| 1 | test_01_user.py |
TC-USER-* | User CRUD |
| 2 | test_02_category.py |
TC-CAT-* | Category CRUD |
| 3 | test_03_rule.py |
TC-RULE-* | Rule CRUD + enforcement |
| 4 | test_04_group.py |
TC-GRP-* | Group CRUD + approval |
| 5 | test_05_post.py |
TC-POST-* | Post CRUD + visibility |
| 6 | test_06_resource.py |
TC-RES-* | Resource CRUD |
| 7 | test_07_interaction.py |
TC-IACT-* | Interaction CRUD |
| 8 | test_08_relations.py |
TC-REL-* | All 9 relation types |
| 9 | test_09_cascade_delete.py |
TC-DEL-* | Cascade delete |
| 10 | test_10_permissions.py |
TC-PERM-* | Access control |
| 11 | test_11_user_journeys.py |
TC-JOUR-* | Integration (sequential) |
| 12 | test_12_resource_transfer.py |
TC-TRANSFER-* | Resource transfer |
| 13 | test_13_user_follow.py |
TC-FRIEND-* | Follow/block |
| 14 | test_14_category_association.py |
TC-STAGE/TRACK/PREREQ/CATREL-* | Category associations |
| 15 | test_15_entry_rules.py |
TC-ENTRY-* | Entry preconditions |
| 16 | test_16_closure_rules.py |
TC-CLOSE-* | Closure rules |
| 17 | test_17_rule_engine.py |
TC-ENGINE-* | Rule engine conditions/actions |
Each file uses isolated data directories for parallel-safe execution. Shared fixtures are in scripts/tests/base.py.
See references/endpoints.md for detailed API examples. See references/schema.md for complete field and enum definitions.
Documentation Sync
This skill's data model is the implementation of the canonical specs in docs/ and specs/. When modifying the skill's schema, engine logic, or data model, must sync the following docs:
| Skill file | Canonical docs | Sync what |
|---|---|---|
references/schema.md |
docs/data-types.md, docs/relationships.md |
Field definitions, enums, required fields, relation schemas |
scripts/engine.py (CRUD logic) |
docs/crud-operations.md, specs/data-integrity.md |
CRUD operations, cascade strategies, uniqueness constraints |
scripts/engine.py (cache) |
specs/cache-strategy.md |
Cache stats triggers, read-only enforcement |
scripts/tests/test_11_user_journeys.py |
docs/user-journeys.md |
User journey steps, data operation sequences |
scripts/tests/test_*.py |
specs/testcases/*.md |
Test cases aligned 1:1 with spec numbering |
Checklist when updating the skill:
- Update skill code (
engine.py) and tests (scripts/tests/test_*.py) - Update skill reference docs (
references/schema.md,references/endpoints.md) - Update canonical docs (
docs/data-types.md,docs/relationships.md,docs/crud-operations.md,docs/user-journeys.md) - Run
uv run python .claude/skills/synnovator/scripts/tests/run_all.pyto verify
Didn't find tool you were looking for?