Reference
Rye Conventions Catalog
Adopt consistent conventions so Rye stays extensible without schema migrations.
Source file: docs/conventions-catalog.md
Rye Conventions Catalog
Type Conventions
Types are open conventions — write a new value and it exists, no migration required.
- Node types (
node_type):person,org,project,task,opportunity,pipeline,ticket,parcel,document,incident,release,component,product - Edge types (
edge_type):employs,assigned_to,project_member,blocks,depends_on,regarding,applied_to,targets,references,affects,triggered_by,contains,impacted,owns,adjacent_to - Assertion types (
assertion_type):project_status,task_status,deal_stage,health_score,churn_risk,sentiment,ownership,title_opinion,interview_feedback,candidate_stage,ticket_status,decision_status - Event types (
event_type):meeting,phone_call,email,escalation,incident_update,interview,agent_query,domain_change,task_created,status_change,comment,time_log,dispute_raised,dispute_resolved,opportunity_created,node_merge,node_properties_updated
Onboarding and plugin metadata add convention-owned infrastructure types:
- Node types:
onboarding_scope,intake_profile,retrieval_channel,intake_run,plugin - Edge types:
scope_uses_profile,scope_enables_plugin,scope_applies_to_source,scope_uses_retrieval_channel,retrieved_via,observed_in_run,expected_by_profile,scope_has_context_gap - Assertion types:
scope_status,scope_purpose,scope_boundary,scope_owner,expected_contexts,holding_context,unexpected_context_policy,blocked_contexts,retention_policy,evidence_policy,review_gate,agent_autonomy_policy,accepted_knowledge_policy,source_of_truth_policy,process_constraint,process_metric,improvement_cycle,convention_registry,plugin_policy_binding - Event types:
onboarding_started,scope_policy_recorded,plugin_policy_bound,onboarding_completed,scope_revision_proposed
Run SELECT rye_catalog() to see which types are in use in a given instance.
Onboarding Scope Convention
Rye onboarding is scope-first. A Rye instance usually starts by assisting one
limited function or workflow. Store that setup as an onboarding_scope node,
not as an organization-wide assumption.
Name the scope after the organizational context, not the source or retrieval
channel. Use labels such as Example Project or Lead Follow-Up; avoid labels
such as Example Slack Pilot or Composio Email Intake unless Slack or
Composio is itself the process being modeled.
Use expected_contexts instead of hard context whitelists. Expected contexts
are known safe routing expectations for a source/profile. If source material
does not match, route it to a holding_context or create a context_gap
candidate according to unexpected_context_policy.
Use blocked_contexts and never_infer for hard boundaries.
The implementation reference lives in:
docs/onboarding.mdschema/migrations/0010_onboarding_scope_plugins.sqlschema/migrations/0013_onboarding_knowledge_policies.sql
Convention Registry Pattern
Use convention_registry assertions when a scope has repeated local vocabulary
that agents should reuse, but the pattern is not stable enough to become a full
plugin.
Each registered convention should include:
labelaliasesdescriptionuse_whenavoid_whenstatus:observed,proposed,accepted,deprecated, orplugin_owned- optional
owning_plugin_id
Use register_scope_convention(...) to write the assertion. Prefer this over
letting fresh agents infer semantics from existing node or edge labels alone.
Source Of Truth Policy Pattern
Use source_of_truth_policy assertions to say which source is authoritative
for a specific status or fact domain.
Each policy should include:
status_domainauthoritative_sourceeffective_atreview_gateevidence_allowedsupersedesnotes
Use record_source_of_truth_policy(...) during onboarding when source authority
is part of the setup. Source names, connector names, folder names, channel
names, or logs are never authority by themselves.
Process Improvement Cycle Pattern
Use improvement_cycle assertions when a scope is about improving an
organizational process. The pattern follows the constraint-oriented improvement
loop:
goalIdentify: current constraintExploit: how to get the most from the current constraintSubordinate: what other work must align to the constraintElevate: when and how to add capacity or change the systemRepeat: when to inspect the next constraintmetricsnext_constraint
Use record_improvement_cycle(...) to store the cycle. The helper also records
a process_constraint assertion for the current constraint. Logs and traces may
support the metrics, but the durable assertion is the reviewed business
knowledge about the process.
Pattern Library Convention
When a domain needs repeatable modeling guidance but not a core migration, define a pattern contract before writing implementation SQL.
A pattern contract should describe:
- node, edge, assertion, event, and artifact type values
- required and optional JSONB fields
- assertion keying and supersession rules
- provenance and artifact rules
- security and classification expectations
- example writes and conformance checks
The pattern library skill provides reusable templates and schema guidance:
skills/rye-pattern-library/SKILL.md
Assertion Key Convention
Use assertion_key to define uniqueness scope for active facts:
- Single-valued facts:
assertion_key = 'default'- Examples:
task_status,deal_stage,project_status,health_score,churn_risk - Replace with
record_assertion(...)for normal accepted writes
- Examples:
- Multi-valued facts: use a stable domain key
ownershipkeyed byowner:<node_id>candidate_stagekeyed byrole:<opportunity_code>interview_feedbackkeyed byround:<round_name>
Rye enforces active uniqueness by subject, assertion type, assertion key, and effective window. This allows a current row and a scheduled future row for the same key to coexist without making future knowledge current too early.
Assertion Write Convention
- Prefer
record_assertion(...)for accepted assertions. It handles current, historical, candidate, and future-effective writes consistently. - Assertion content is immutable after insert. Only lifecycle metadata and effective-window narrowing may be updated by Rye helper functions.
- Use
supersede_assertion(...)only when replacing a known assertion by id and you do not need future-scheduling behavior. - Use
contest_assertion(...)when contradictory information arrives but you’re uncertain which is correct. Both claims coexist until resolved. - Use
resolve_dispute(...)to pick a winner among competing assertions. - Do not run direct
UPDATE assertions— RLS blocks it outside the supersession function context.
Future Assertion And Planning Pattern
Use this pattern when an accepted future change should be visible for planning but not treated as current truth.
- Store the plan as current-visible knowledge.
- Examples:
deal_stage_plan,task_status_plan,milestone_status_plan. - Include owner, target/effective date, status, dependencies, risks, and the scheduled assertion id when available.
- Examples:
- Store the future truth as a future-effective assertion.
- Use the same
assertion_keyas the current fact it will replace. - Set
effective_atto the cutover date. - Let
record_assertion(...)close the current row’seffective_to.
- Use the same
- Read current truth from
current_valid_assertions. - Read future or historical truth from
assertions_as_of(...).
Use CRM/PM helpers when available:
schedule_deal_stage_change(...)schedule_task_status_change(...)schedule_milestone_status_change(...)
Do not report a plan as already true. A plan says “we intend this”; the future-effective assertion says “Rye should answer this as true at that time.”
Assertion Dispute Convention
When new information contradicts an existing assertion but the correct answer is uncertain:
- Call
contest_assertion(existing_id, new_claim, source, confidence, reason). - The competing assertion uses
assertion_key = 'contested:<source>'so both coexist. - A
dispute_raisedevent is recorded for audit. - Query
active_disputesto find all unresolved conflicts. - Call
resolve_dispute(winning_assertion_id, reason, actor)to resolve. - A
dispute_resolvedevent is recorded. Losers are superseded. If the winner had acontested:key, it’s promoted todefault.
-- Contest an existing ownership assertion
SELECT contest_assertion(
p_existing_assertion_id := '<assertion_uuid>',
p_new_claim := '{"fraction": 0.125}',
p_source := 'county_filing_2024_0892',
p_confidence := 0.7,
p_reason := 'County filing shows different fraction'
);
-- Find unresolved disputes
SELECT * FROM active_disputes;
-- Resolve in favor of the contested assertion
SELECT resolve_dispute(
p_winning_assertion_id := '<contested_assertion_uuid>',
p_reason := 'Confirmed by title examiner',
p_actor := 'user:alice'
);
Artifact Convention
- Use
record_artifact()for all artifact creation. - Pass
p_content_hashto prevent duplicate artifacts from the same source material. - If a matching artifact exists (same type and content hash), returns the existing ID.
- Agents can create artifacts (INSERT is allowed for all roles).
SELECT record_artifact(
p_artifact_type := 'document_parse',
p_content := '{"title": "Q4 Report", "sections": [...]}',
p_source_event_id := '<parse_event_uuid>',
p_source_node_id := '<document_node_uuid>',
p_content_hash := 'sha256:abc123...'
);
Tabular Intake Convention
When source data arrives as CSV or XLSX files instead of live domain tables:
- inspect first, then confirm mappings with the user before writing transforms
- keep extraction lossless by preserving source column names and raw row values
- use NDJSON as the interchange format between extract, map, and stage steps
- treat
tabular_commit_rye.mtsas the only database write boundary - use
run_idas the run identity andrun_fingerprint_sha1as duplicate protection - reject repeated source content by default unless the operator explicitly allows a replay
The reference implementation for this convention lives in:
skills/rye-tabular-intake/SKILL.md
Event Convention
- Use
record_event()for all event creation. Never insert intoeventsandevent_participantsseparately. - Every event should have at least one participant. Events with no participants are invisible under RLS.
- Use
p_actorto identify who or what caused the event (e.g.,'user:alice','agent:triage-bot','system:cdc'). - Events are immutable — never update or delete them.
Classification Convention
- Nodes with
attrs->'teams'(non-empty array) must haveattrs->>'classification'set. - The classification enforcement trigger rejects nodes with teams but no classification.
- Valid classification values:
internal,confidential,restricted(or other domain-appropriate values). - Nodes without teams or classification are public — visible to all users.
-- Team-scoped node (classification required)
INSERT INTO nodes (node_type, label, attrs)
VALUES ('task', 'Build feature X',
'{"classification": "internal", "teams": ["engineering"]}');
-- Public node (no classification needed)
INSERT INTO nodes (node_type, label, properties)
VALUES ('pipeline', 'Sales Pipeline', '{"code": "PL-SALES"}');
Node Property Update Convention
When the graph node IS the system of record (no backing domain table), use update_node_properties() to update its properties. This is the only way agents can modify nodes — direct UPDATE nodes is blocked by RLS.
- Properties are merged via
||(new keys overlay old, existing keys preserved). - Optionally updates
labelif provided. - Returns the UUID of a
node_properties_updatedaudit event withchanged_fieldscontainingproperties_before,properties_after,properties_added, and optionallylabel_before/label_after. - Archived nodes raise an exception.
SELECT update_node_properties(
p_node_id := '<node_uuid>',
p_properties := '{"email": "jane@new.com", "title": "VP Engineering"}',
p_summary := 'Updated contact info from sales call'
);
For nodes backed by a domain table, update the domain table instead — CDC will propagate the change via domain_change events.
Domain Integration Convention
Domain tables are the system of record. Rye connects them without modifying them.
- Use
link_record(schema, table, id, node_type, label, properties)to connect domain table rows to the graph. Each distinctsource_idcreates a new node; same(schema, table, source_id)updates the existing one. Looks upnode_source_mapfirst, thenexternal_id/external_source. - Use
link_records_batch(schema, table, ids[], type, labels[], properties[])for bulk imports — processes multiple records in a single call. - Use
track_table(schema, table)to attach CDC triggers for automatic change tracking. Supports tables with any PK column name. - CDC events have type
domain_changeand includechanged_fieldswith before/after diffs. - Only rows with a linked node (in
node_source_map) produce CDC events. Unlinked rows are silently skipped.
Human-Readable Code Convention
Codes follow the format {PREFIX}-{YYMM}-{SEQ} (e.g., OPP-2403-0042, TSK-2403-0187).
- Generated by
generate_crm_code(prefix). - Counters reset per prefix per month.
- Concurrency-safe via
INSERT ... ON CONFLICT DO UPDATE.
Edge Temporal Convention
- Active edges:
archived_at IS NULL. - Temporal bounds:
effective_from/effective_to. - To end a relationship, set
archived_atoreffective_to. Do not delete edges.
Soft Delete Convention
- All core tables use
archived_atfor soft deletion. archived_at IS NULL= active.- Views and queries filter on
archived_at IS NULLby default.
Session Variable Convention
Authorization uses session variables, not database roles:
SET LOCAL "app.current_user_id" = 'user:alice';
SET LOCAL "app.current_teams" = 'engineering,sales';
SET LOCAL "app.current_role" = 'team_member';
Role hierarchy: admin > manager > team_member > viewer > agent.
View Convention
All views must use security_invoker = true (PostgreSQL 15+) so that RLS policies are evaluated using the calling session’s permissions.
| View | Purpose |
|---|---|
current_assertions | Non-superseded assertions only |
node_context | Full node context with edges and assertions |
nodes_secure | Nodes with field-level redaction applied |
active_disputes | Subjects with competing active assertions |
Materialized View Convention
Profile materialized views (opportunities_active, contacts_directory, task_board) need periodic refreshing.
- Use
refresh_materialized_views()to refresh all installed profile views. - Uses
CONCURRENTLY— reads continue during refresh. - Safe to call regardless of which profiles are installed.
Security Configuration Convention
Security gating is data-driven. To add a new sensitive assertion type or role:
- Insert into
assertion_type_accessto gate read/write on specific assertion types. - Insert into
role_classification_accessto define which classification levels a role can access. - No SQL policy changes or migrations needed for new types or roles.
Profiles
- CRM profile:
schema/migrations/0100_profile_crm.sql - PM profile:
schema/migrations/0110_profile_pm.sql - Profile migrations use
*_profile_<name>.sqlnaming. - Enable during install with
--profiles crm,pm.