Utilities for the Syndicated Actor Model
  • Nim 98.8%
  • jq 0.7%
  • Nix 0.5%
Find a file
Emery Hemingway 4b67ec48f4
Peer Production License
This license already propagated from dependencies.
2026-03-20 00:00:00 +00:00
doc icmp-rtt-actor: resurrected ping utility 2026-01-08 12:00:00 +00:00
LICENSES icmp-rtt-actor: resurrected ping utility 2026-01-08 12:00:00 +00:00
src Peer Production License 2026-03-20 00:00:00 +00:00
.gitignore icmp-rtt-actor: resurrected ping utility 2026-01-08 12:00:00 +00:00
config.prs Update dependencies and rewrite 2025-12-05 00:00:00 +00:00
default.nix Update dependencies and rewrite 2025-12-05 00:00:00 +00:00
file_system.prs file_system: add write-text and remove-file 2024-09-26 12:47:14 +01:00
icmp_rtt_actor.prs icmp-rtt-actor: resurrected ping utility 2026-01-08 12:00:00 +00:00
mpv.config-example.pr Adjust to Syndicate-nim changes 2023-05-18 12:41:52 +01:00
process_proxy.prs process-proxy: observable PID 2025-12-26 00:00:00 +00:00
README.md icmp-rtt-actor: resurrected ping utility 2026-01-08 12:00:00 +00:00
sbom.json Peer Production License 2026-03-20 00:00:00 +00:00
syn_agent.prs syn-agent: add more options and sturdyref minting 2025-12-18 12:00:00 +00:00
syndicate_utils.nimble *.nimble: swap nim:bin key and value 2024-09-30 16:41:01 +01:00
Tupfile Generate .envrc with Tup 2024-12-09 08:42:30 +00:00
Tuprules.jq Generate .envrc with Tup 2024-12-09 08:42:30 +00:00
Tuprules.tup Update dependencies, use new rpc API 2026-03-20 00:00:00 +00:00
utils.prs Update dependencies and rewrite 2025-12-05 00:00:00 +00:00

Syndicate utils

Most utilities accept the --route:ROUTE flag to specify a Syndicate peer with a fallback to $SYNDICATE_ROUTE.

icmp-rtt-actor

See the man page.

process-proxy

The process-proxy utility adds a few process management features not provided by the syndicate-server. process-proxy will fork a proxy process that communicates with the syndicate-server over stdio and then will exec its argv. Startup notification is enabled by passing -n $FD before the arguments to exec.

Features

  • s6-style startup notification to Syndicate readyness.
  • Syndicate messages to Unix signals.

See the process_proxy schema for more information.

Configuration example

#!/usr/bin/env syndicate-server -S --config

<require-service <daemon example>>

<daemon example {
  argv: [
    # Watch FD 3 for ready notification.
    "process-proxy" "-n" "3"
    # Use trap from execline to dispatch signals.
    "trap"
    " SIGUSR1"
      # Indicate ready on SIGUSR1 by writing a newline to FD 3.
    "  fdmove"
    "  1"
    "  3"
    "  echo"
    " "
    " SIGUSR2"
    "  ps"
    "  -o"
    "  ppid,pid,pgid,args"
    " "
    ""
    # Pause indefinitely.
    "s6-pause"
  ]
  readyOnStart: #f
  protocol: application/syndicate
}>

# Get a ref for the process-proxy.
? <service-object <daemon example> ?obj> [
  # Subscribe to a ready notification with a rewrite to the config dataspace.
  $obj += <notify-ready <* $config [ <rewrite #t <service-state <daemon example> ready>> > ]>

  # When the example is started send it SIGUSR1.
  ? <service-state <daemon example> started> [
    $obj ! <signal SIGUSR1>
  ]

  # When the example is ready send it SIGUSR2.
  ? <service-state <daemon example> ready> [
    $obj ! <signal SIGUSR2>
  ]
]

? <service-state <daemon ?svs> ?state> [
  $log ! <log "-" { service: <daemon $svs> line: $state }>
]

syn-agent

An ephemeral Syndicate gatekeeper inspired by ssh-agent.

See the man page.

Syndesizer

A Syndicate multitool that includes a number of different actors that become active via configuration.

Whether you use a single instance for many protocols or many specialized instances is up to you.

Cache

Observes patterns and reässert the values captured for a given lifetime. Takes the argument <cache { dataspace: #!any lifetime: float }>. The lifetime of a cache counts down from moment a value is asserted.

Example configuration:

? <nixspace ?nixspace> [
  ; Require the nix_actor during observations.
  ?nixspace> ? <Observe <rec eval _> _> [
    $config <require-service <daemon nix_actor>> ]
  ?nixspace> ? <Observe <rec realise _> _> [
    $config <require-service <daemon nix_actor>> ]

  ; Cache anything captured by observers in the $nixspace for an hour.
  ; The nix_actor is not required during caching.
  $config <require-service <daemon syndesizer>>
  $config ? <service-object <daemon syndesizer> ?cap> [
    $cap <cache { dataspace: $nixspace lifetime: 3600.0 }> ]
]

File System Usage

Summarize the size of file-system directory. Equivalent to du -s -b. Query the size of a directory in bytes by observing <file-system-usage "/SOME/PATH" ?size>.

# Configuration example

? <exposed-dataspace ?ds> [

  <require-service <daemon syndesizer>>
  ? <service-object <daemon syndesizer> ?cap> [
    $cap <file-system-usage { dataspace: $ds }>
  ]

]

HTTP driver

Experimental HTTP server that services requests using some version of the http Syndicate protocol schema.

#### Configuration example

let ?not-found = dataspace
$not-found ? <request _ ?res> [
  $res ! <status 503 "Service unavailable">
  $res ! <done "No binding here.">
]

let ?greeting = dataspace
$greeting ? <request _ ?res> [
  $res ! <status 200 "ok">
  $res ! <chunk "Hello world">
  $res ! <done "!">
]

let ?http = dataspace
$http [
  <http-bind #f 80 get [ ] $not-found>
  <http-bind #f 80 get [|...|] $not-found>
  <http-bind #f 80 get ["hello"] $greeting>
]

? <service-object <daemon http-driver> ?cap> [
  $cap <http-driver { dataspace: $http }>
]

<daemon http-driver {
  argv: [ "/bin/syndesizer" ]
  clearEnv: #t
  protocol: application/syndicate
}>

<require-service <daemon http-driver>>

JSON Socket Translator

Communicate with sockets that send and receive lines of JSON using <send …> and <recv …> messages. Responds to the gatekeeper step <json-socket-translator { socket: <unix "…"> / <tcp "…" … }> $resolver>.

# MPV configuration example
<require-service <daemon mpv-server>>

<daemon mpv-server {
  argv: [
    "/run/current-system/sw/bin/mpv"
    "--really-quiet"
    "--idle=yes"
    "--no-audio-display"
    "--input-ipc-server=/run/user/1000/mpv.sock"
    "--volume=75"
  ]
  protocol: none
}>

let ?resolver = dataspace
$resolver ? <accepted ?mpvSpace> $mpvSpace [
  # announce the dataspace when the translator is connected
  $config <mpv $mpvSpace>
  $config <bind <ref { oid: "mpv" key: #x"" }> $mpvSpace #f>

  # translate <play-file …> to an MPV command
  ?? <play-file ?file> [
    ! <send { "command": ["loadfile" $file "append-play"] }>
  ]

  # clear the playlist on idle so it doesn't grow indefinitely
  ?? <recv {"event": "idle"}> [
    ! <send { "command": ["playlist-clear"] }>
  ]
]

? <service-state <daemon mpv-server> ready> [
  <require-service <daemon syndesizer>>
  ? <service-object <daemon syndesizer> ?cap> [
    $cap <resolve <json-socket-translator {
        socket: <unix "/run/user/1000/mpv.sock">
      }> $resolver>
  ]
]

JSON Input Adapter

Parse JSON from a open file-descriptor and send as messages.

# Configuration example
<require-service <daemon syndesizer>>

<daemon syndesizer {
  argv: [
    "redirfd" "-r" "3" "/etc/foo.json"
    "syndesizer"
  ]
  protocol: application/syndicate
}>

? <service-object <daemon syndesizer> ?obj> [
  $obj <json-input-adapter { input: 3 target: <* $log [<rewrite ?any <log "-" { line: $any }>> ]>  }>
]

Pulse proxy

An actor that makes an assertion within a pulsed timeframe. This can be used to implement polling behavior or periodic service scheduling.

#!/usr/bin/env -S syndicate-server --config

let ?destination = dataspace
$destination ? ?x [
  $log ! <log "destination" { +: $x }>
  ?- $log ! <log "destination" { -: $x }>
]

# Request a pulse service.
<q <service pulse {
    label: "pulse-demo" # Not used by the pulse service, just here to match to the answer.
    assertion: <pulse-active>
    target: $destination
    frequency: 4.0 # Four hertz pulse cycle.
    duty-factor: 0.5 # Assertions forwarded half the time.
    dither: 1.0 # Dither the cycle period to a standard deviation of 1 hertz.
  }>>

# Start the pulse service on demand.
? <q <service pulse ?detail>> [
  <require-service <daemon syndesizer>>
  ? <service-object <daemon syndesizer> ?obj> [
    let ?rewriter = <* $config [<rewrite ?resp <a <service pulse $detail> $resp>>]>
    $obj <resolve <pulse $detail> $rewriter>
  ]
  <daemon syndesizer {
    argv: "syndesizer"
    clearEnv: #t
    protocol: application/syndicate
  }>
]

# Log if a service request is rejected.
? <a <service ?label ?detail> <rejected ?reason>> [
  $log ! <log "service request rejected" { line: $reason label: $label detail: $detail }>
]

XML translator

Translates between Preserves and XML according to the Conventions for Common Data Types.

Examples:

  • <xml-translation "<foo a=\"1\"> <bar>hello world!</bar></foo>" <foo {"a": 1}<bar "hello world!">>>
  • <xml-translation "" [#t #f]>
  • <xml-translation "<<</>>" #f>
# Configuration example
? <sharedspace ?ds> [
  $ds ? <Observe <rec xml-translation _> _> $config [
    $config <require-service <daemon syndesizer>>
    $config ? <service-object <daemon syndesizer> ?cap> [
      $cap <xml-translator { dataspace: $ds }>
    ]
  ]
]

http-client

The inverse of http-driver.

Caveats

  • HTTPS is assumed unless the request is to port 80.
  • If the request or response sets Content-Type to application/json or …/preserves the body will be a parsed Preserves value.
  • No caching or proxying.
  • Internal errors propagate using a 400 Internal client error response.

Sample Syndicate server script:

#!/usr/bin/env -S syndicate-server --control --config

# A dataspace for handling the HTTP response.
let ?response-handler = dataspace
$response-handler [
  ?? <done { "code": "EUR" "exchange_middle": ?middle } > [
    $log ! <log "-" { line: <exchange EUR RSD $middle> }>
    $control <exit 0>
  ]
]

# A dataspace for collecting a dataspace from the http-client.
let ?client-resolver = dataspace
$client-resolver ? <accepted ?client> $client [
  <request
    # Request Dinar to Euro exchange rate.
    <http-request 0 "kurs.resenje.org" 443
      get ["api" "v1" "currencies" "eur" "rates" "today"]
      {content-type: "application/json"} {} #f
    >
    $response-handler
  >
]

# Pass the resolver dataspace to the client.
? <service-object <daemon http-client> ?cap> [
  $cap <resolve <http-client { response-content-type-override: "" }> $client-resolver>
]

<require-service <daemon http-client>>

<daemon http-client {
  argv: [ "/bin/http-client" ]
  clearEnv: #t
  env: {
    BUILD_SUM: $sum
  }
  protocol: application/syndicate
}>

mintsturdyref

A utility for minting Sturdyrefs.

msg

A utility that parses its command-line arguments as Preserves and send them as messages to $SYNDICATE_ROUTE. When called as assert (by a symlink or a rename) it will make assertions instead.

preserve_process_environment

This utility serializes it's process environment to Preserves and prints it to stdout. It can be used to feed the environment variables of a nested child of the Syndicate server back to the server. For example, to retreive the environmental variables that a desktop manager passed on to its children.

syndump

Utility for printing assertions and messages. Parses the command-line arguments as a pattern, connects a dataspace via $SYNDICATE_ROUTE, and writes observations to standard-output. Published assertions are prefixed by the + character, retractions by -, and messages by !.

Accepts the following options:

  • --json -j Output in a JSON compatible syntax if possible.
  • --caveat:CAVEAT Rewrite respones by CAVEAT. Caveats are applied before paths.
  • --path:PATH Project responses by Preserves PATH.
  • --exit Exit after receiving responses.

Example

# Print patterns in use, filter down with AWK to only the published patterns.
$ FS=':' syndump '<Observe ? _>' | awk -F : '/^+/ { print $2 }'

synqa

Utility for the question and answer pattern. Command-line arguments are published in <q> records to $SYNDICATE_ROUTE and the corresponding <a> responses are written to stdout.

Accepts the following options:

  • --json -j Output in a JSON compatible syntax if possible.
  • --caveat:CAVEAT Rewrite respones by CAVEAT. Caveats are applied before paths.
  • --path:PATH Project responses by Preserves PATH.
  • --exit Exit after receiving responses.