name: create-relationship description: Use when connecting LikeC4 elements and you need to choose the exact logical or deployment relationship kind, place technology in the right field, or decide whether a connection belongs in the model or only in deployment.
Create LikeC4 Relationship
Goal
Choose the exact relationship, explain the rule briefly, and show a paste-ready example.
Default answer shape:
- relationship choice
- short rule
- minimal example
- counter-example / anti-pattern
- handoff to
create-sequence-viewonly if timing or fallback order matters
When to Use
- Connecting two existing elements in the logical model
- Choosing between
calls,async,reads,writes, oruses - Deciding whether the connection belongs in
model {}or deployment - Placing protocol or medium details such as
Manual,HTTPS,HTTP/8080,AMQP, orLDAP - Modeling queue/event flows without inventing return paths
Do not use to create the elements themselves — use create-element first.
Local taxonomy to respect in this repository
Model relationship kinds
uses, calls, async, reads, writes
Deployment relationship kinds
http, https, tcp, nfs, amqp, oidc_saml, ldap, sql, redis, smtp
Normal application traffic belongs in the system model with a model relationship kind plus technology '...'. Deployment relationships are reserved for infrastructure-only exceptions.
Quick decision table
| Need | Use | Avoid |
|---|---|---|
| Service invokes service | -[calls]-> |
inventing invokes |
| Read from cache/database/directory | -[reads]-> |
-[calls]-> to data stores |
| Persist or mutate data | -[writes]-> |
generic calls for persistence |
| Queue/event flow | -[async]-> |
return arrows to the producer |
| Human interaction | -[calls]-> + technology 'Manual' |
deployment-only browser traffic |
| Protocol detail | technology 'HTTPS', technology 'HTTP/8080', technology 'AMQP' |
putting protocol into model relationship kind |
Teach by contrast
Service-to-service request
webApp -[calls]-> api 'Sends request' {
technology 'HTTPS'
}
// ❌ Wrong: kind in block
webApp -> api {
calls 'Sends request'
technology 'HTTPS'
}
Reads vs calls
Use calls for service behavior, reads for data access.
retrievalService -[reads]-> redisCache 'Checks cache'
retrievalService -[reads]-> primaryDatabase 'Fetches on cache miss'
// ❌ Wrong: databases modeled as generic service calls
retrievalService -[calls]-> primaryDatabase 'Fetch data'
Writes for persistence
worker -[writes]-> primaryDatabase 'Stores processing result' {
technology 'PostgreSQL'
}
Async queue/worker flow
uploadService -[async]-> jobQueue 'Publishes job' {
technology 'AMQP'
}
worker -[async]-> jobQueue 'Consumes job' {
technology 'AMQP'
}
worker -[writes]-> primaryDatabase 'Stores result' {
technology 'PostgreSQL'
}
// ❌ Wrong: fake return path from async worker to producer
worker -[calls]-> uploadService 'Send completion'
Cache fallback is two reads, not a smart composite kind
api -[reads]-> redisCache 'Checks cache'
api -[reads]-> primaryDatabase 'Fetches on cache miss'
api -[writes]-> redisCache 'Refreshes cached value'
// ❌ Wrong: invented behavior-specific kind
api -[reads_with_fallback]-> primaryDatabase
If fallback timing or retries matter, keep the model relationships explicit and move the temporal story to create-sequence-view.
Model first, deployment rarely
Prefer this:
user -[calls]-> webApp 'Uses UI' {
technology 'Manual'
}
webApp -[calls]-> api 'Sends request' {
technology 'HTTPS'
}
api -[calls]-> internalService 'Routes request' {
technology 'HTTP/8080'
}
Not this:
// ❌ Duplicating normal app traffic in deployment
Prod.Web.webApp -[https]-> Prod.App.apiApp 'Browser traffic'
Use a deployment relationship only when the logical model does not already express the fact: monitoring scrapes, replication, bastion access, storage mounts, or an operational network hop.
Relationship documentation standard
Always think in this order:
- Kind —
calls,async,reads,writes,uses - Label — short action phrase such as
Queues job,Fetches records,Authenticates user - Technology — protocol or medium only (
Manual,HTTPS,HTTP/8080,AMQP,LDAP,SMTP,PostgreSQL) - Description — optional, only when the label is still ambiguous
If MCP is unavailable
Stay specific:
- inspect
projects/shared/SPEC_CHEATSHEET.mdandprojects/shared/spec-*.c4 - verify whether you are in logical model vs deployment files
- answer with the rule and the minimal example immediately
- list the follow-up checks to run later (
find-relationships,read-project-summary, preview affected views)
Do not fall back to generic “it depends” wording when the repository taxonomy already tells you the right relationship family.
Common mistakes
❌ api -> service 'Call endpoint' // Missing relationship kind
❌ api -> service { calls 'Call endpoint' } // Kind in block
❌ api -[invokes]-> service // Invalid undeclared kind
❌ api -[reads_with_fallback]-> database // Composite kind invented for behavior
❌ worker -[calls]-> uploadService 'Send completion' // Fake return path in async flow
❌ Prod.Web.webApp -[https]-> Prod.App.apiApp // Duplicated normal app traffic in deployment
Handoffs
- Need the endpoints first? Use
create-element - Need the exact kinds available in the workspace? Use
lookup-element-kinds - Need retries, callbacks, fallback order, or webhook timing? Use
create-sequence-view