Run a site
What a site offers
Anahita is small services, each doing one thing, and a site runs and shows
only what it offers. One file says what that is: instance.json, beside
the files that say what each kind of profile has. An instance is one big
profile, and every profile on it has only what it has. A site of notes and
photos alone, for example, offers no articles, topics, events, websites or
videos: they are in no composer, menu or tab, and the services refuse them.
Built for the recipes, roadmap row 139 (the plan (opens in a new tab)).
The file
instance.json in the directory ACTOR_FEATURES_PATH names,
/app/defaults/actor_features in graph-grpc-service's image, beside
default.json, person.json, group.json, event.json and
website.json (Permissions). It is in their
form: a list of services, each with the kinds it offers.
[
{ "service": "actor-service", "node_types": ["person", "group"] },
{ "service": "text-service", "node_types": ["note"] },
{ "service": "photo-service", "node_types": ["photo"] },
{ "service": "video-service", "enabled": false }
]
That is a site of people and groups, notes and photos.
| In the file | Means |
|---|---|
A service with node_types |
That service, with those kinds alone |
A service with "enabled": false |
Not that service at all |
| A service not listed | As each kind of profile's own file says |
| No file | Everything, as before it was read. The image carries none |
actor-service's kinds are the kinds of profile that may be made: group,
event, and website, which syndication-service makes. A person is always
offered: it is an account. The kinds of post are note, article and
topic (text-service), photo (photo-service), and video and audio
(video-service).
A file that cannot be read is said in graph-grpc-service's log, and offers everything, as no file does.
What follows from it
- Every profile has only what the instance offers, whatever its kind's file or its own saved choices say: its composers and tabs, and who may add each kind, come from those features, so a kind that is off is neither shown nor taken.
- The services refuse what is off, with 403
{"error": "off"}: actor-service a group or an event, syndication-service a website, text-service a note, an article or a topic, photo-service a photo, and video-service a video or a sound. graph-grpc-service refuses to save a post of a kind that is off, whichever service asks, as a last check.GROUPS_FROM,EVENTS_FROMandWEBSITES_FROMstill say who may make one where it is offered. - What is already there stays, readable at its address: a site that turns articles off keeps those written before.
- Posts from other servers are shown as they are: an article from the fediverse still shows in a feed. This is about what is made here.
- NodeInfo says what is offered, in
metadata.offers:{"profiles": ["person", "group"], "posts": ["note", "photo"]}. The web app follows it: its menu (Groups, Events, Websites), a group's Events tab, the recommendations' tabs, and the buttons that make a group, an event or a website.
Video and sound
VIDEO_UPLOADS and AUDIO_UPLOADS go together with the file: video is
offered where the file offers it and VIDEO_UPLOADS is on, sound the
same with AUDIO_UPLOADS (Configuration). A
site that set them changes nothing. NodeInfo's videoUploads and
audioUploads say both together.
Giving a site its own
graph-grpc-service alone reads the file; every other service asks it
(ReadInstance, on the graph's gRPC service), so there is one file in one
place.
- docker-compose:
graph-grpc-defaults/actor_features/is mounted into graph-grpc-service; putinstance.jsonthere. It is read again for each request: no restart. - Kubernetes: mount a ConfigMap of the file over
/app/defaults/actor_features/instance.jsonin graph-grpc-service's Deployment, withsubPath, so that the image's other files stay. A recipe does this in its overlay.
Where the code is
| What | Where |
|---|---|
| Reading the file, cutting a profile's features, what is offered | graph-grpc-service/data/actor_features/instance.go, merger.go (ForSite) |
ReadInstance, and the last check on saving a post |
graph-grpc-service/cmd/server/handlers/instance.go |
Asking, and refusing with off |
anahita-libs/data/services/graph_grpc.go (ReadInstance, Offered), anahita-libs/handlers/offered.go |
NodeInfo's offers |
auth-service/cmd/api/handlers/node_info.go |
| The web app | src/utils/offers.js, src/permissions/actor.js (anahita-web) |
From anahitasocial/anahita-services, 2026-11-09.
Written by Claude, reviewed by Rastin Mehr · About this