Here is the surface in one place. Rust groups methods under accessors and takes option structs. Node and Python put methods directly on the client with plain arguments. Go uses methods on its Forge handle. Node and Python also expose native JSON handles from the main import (forge.queue<T>("emails"), forge.queue("emails")) so application payloads stay typed without a separate overlay.
import { ForgeClient } from " forgelib " ;
const forge = await ForgeClient . init (); // reads ./forge.toml
const forge2 = await ForgeClient . initFrom ( " path/forge.toml " );
forge = await forgelib.ForgeClient. init () # reads ./forge.toml
forge = await forgelib.ForgeClient. init_from ( " path/forge.toml " )
let forge = forgelib :: Forge :: init () . await ? ; // reads ./forge.toml
let forge = forgelib :: Forge :: init_from ( " path/forge.toml " ) . await ? ;
let forge = forgelib :: Forge :: init_from_str ( toml ) . await ? ;
// inject your own backend for one primitive, leave the rest on Postgres
let forge = forgelib :: Forge :: builder () . kv ( custom_kv ) . build () . await ? ;
forgeClient , err := forge . InitDefault ( ctx ) // reads ./forge.toml
forgeClient2 , err := forge . InitFrom ( ctx , " path/forge.toml " )
The memory test factories inject a manual clock and seeded, non-cryptographic entropy. Advancing time drives KV TTLs, sessions and tokens, delayed jobs, retry availability, rate-limit refill, and schedules without sleeping. Never use seeded entropy for production credentials.
const config = ' [forge] \n mode = "memory" \n environment = "test" \n ' ;
const forge = await ForgeClient . initMemoryForTesting (config , Date . UTC ( 2026 , 0 , 1 ) , 42 );
forge . advanceTestClock ( 60 ); // seconds
config = ' [forge] \n mode = "memory" \n environment = "test" \n '
forge = await forgelib.ForgeClient. init_memory_for_testing ( config , 1_767_225_600_000 , 42 )
forge. advance_test_clock ( 60.0 ) # seconds
let forge = forgelib :: Forge :: init_memory_for_testing ( config , SystemTime :: UNIX_EPOCH , 42 ) . await ? ;
forge . advance_test_clock (Duration :: from_secs ( 60 )) ? ;
clock := forge . NewManualClock ( time . Unix ( 0 , 0 ))
client , err := forge . NewMemoryForTesting ( config , forge.TestOptions{
Random : forge . NewSeededReader ( 42 ),
if err != nil { return err }
if err := client . AdvanceTestClock ( time . Minute ); err != nil { return err }
Rust’s testing::TestDatabase::new() creates and later drops one isolated PostgreSQL database using the maintenance URL in TEST_DATABASE_URL; integration tests never reuse an application database. The repository’s Node, Python, and Go conformance runners follow the same per-run isolation model. The CI integration job sets a sentinel that turns a missing database URL into failure rather than a skipped pass.
Operation
Rust
Node
Python
Go
Get
kv().get
kvGet
kv_get
KVGet
Set (TTL, NX, XX)
kv().set
kvSet
kv_set
KVSet
Get many
kv().mget
kvMget
kv_mget
KVMGet
Increment
kv().incr
kvIncr
kv_incr
KVIncr
Delete
kv().delete
kvDelete
kv_delete
KVDelete
Exists
kv().exists
kvExists
kv_exists
KVExists
Set TTL
kv().expire
kvExpire
kv_expire
KVExpire
Compare and swap
kv().compare_and_swap
kvCompareAndSwap
kv_compare_and_swap
KVCompareAndSwap
Prefix scan
kv().scan
kvScan, kvScanPage
kv_scan, kv_scan_page
KVScan
Operation
Rust
Node
Python
Go
Enqueue
queue().enqueue
queueEnqueue
queue_enqueue
Enqueue
Batch enqueue
queue().enqueue_batch
queueEnqueueBatch
queue_enqueue_batch
EnqueueBatch
Lease a job
queue().dequeue
queueDequeue
queue_dequeue
Dequeue
Batch lease
queue().dequeue_batch
queueDequeueBatch
queue_dequeue_batch
DequeueBatch
Ack
queue().ack
queueAck
queue_ack
Ack
Nack
queue().nack
queueNack
queue_nack
Nack
Extend the lease
queue().heartbeat
queueHeartbeat
queue_heartbeat
Heartbeat
Depth and oldest age
queue().depth
queueDepth
queue_depth
Depth
Pause / resume
queue().pause, resume
queuePause, queueResume
queue_pause, queue_resume
PauseQueue, ResumeQueue
Throughput stats
queue().stats
queueStats
queue_stats
QueueStats
Inspect dead letters
queue().dead_letters
queueDeadLetters
queue_dead_letters
DeadLetters
Redrive
queue().redrive
queueRedrive
queue_redrive
Redrive
Purge dry-run / confirmed
queue().purge_dead_letters_*
queuePurgeDeadLetters*
queue_purge_dead_letters*
PurgeDeadLetters*
Managed worker
worker(name)
worker(name, handler)
worker(name, handler)
RunWorker
Outbox relay pass
run_outbox_once
runOutboxOnce
run_outbox_once
RunOutboxOnce
Continuous outbox relay
run_outbox_relay_until
runOutboxRelay
run_outbox_relay
RunOutboxRelay
Operation
Rust
Node
Python
Go
Publish
pubsub().publish
pubsubPublish
pubsub_publish
Publish
Subscribe
pubsub().subscribe
pubsubSubscribe
pubsub_subscribe
Subscribe
Channel name
pubsub().channel_for
pubsubChannel
pubsub_channel
PubsubChannel
Operation
Rust
Node
Python
Go
Put
blob().put
blobPut, blobPutObject
blob_put, blob_put_object
BlobPut
Get
blob().get
blobGet
blob_get
BlobGet, BlobOpen
Head (metadata)
blob().head
blobHead
blob_head
BlobHead
Delete
blob().delete
blobDelete
blob_delete
BlobDelete
List
blob().list
blobList
blob_list
BlobList
Presign download
blob().presign_download
blobPresignDownload
blob_presign_download
BlobPresignDownload
Presign upload
blob().presign_upload
blobPresignUpload
blob_presign_upload
BlobPresignUpload
Operation
Rust
Node
Python
Go
Hash password
auth().hash_password
hashPassword
hash_password
HashPassword
Verify password
auth().verify_password
verifyPassword
verify_password
VerifyPassword
Needs rehash
auth().needs_rehash
needsRehash
needs_rehash
NeedsRehash
Create session
auth().create_session
createSession
create_session
CreateSession
Validate session
auth().validate_session
validateSession
validate_session
ValidateSession
Revoke session
auth().revoke_session
revokeSession
revoke_session
RevokeSession
Create API key
auth().create_api_key
createApiKey
create_api_key
CreateAPIKey
Verify API key
auth().verify_api_key
verifyApiKey
verify_api_key
VerifyAPIKey
Create one-time token
auth().create_token
createToken
create_token
CreateToken
Consume one-time token
auth().consume_token
consumeToken
consume_token
ConsumeToken
Operation
Rust
Node
Python
Go
Check and consume
ratelimit().check, check_with
rateLimitCheck
rate_limit_check
RateLimitCheck
Operation
Rust
Node
Python
Go
Cron
schedule().cron
scheduleCron
schedule_cron
ScheduleCron
One-off
schedule().at
scheduleAt
schedule_at
ScheduleAt
Cancel
schedule().cancel
scheduleCancel
schedule_cancel
ScheduleCancel
List
schedule().list
scheduleList
schedule_list
ScheduleList
Tick once
run_scheduler_once
runSchedulerOnce
run_scheduler_once
RunSchedulerOnce
Operation
Rust
Node
Python
Go
Get value
config().get_raw
configGet
config_get
ConfigGet
Set value
config().set_raw
configSet
config_set
ConfigSet
Delete value
config().delete_raw
configDelete
config_delete
ConfigDelete
Evaluate a flag
config().flag
flag
flag
Flag
Set a flag
config().set_flag
setFlagPercent, setFlagOn, setFlagOff, setFlagAllowList
set_flag_percent, set_flag_on, set_flag_off, set_flag_allow_list
SetFlag
Delete a flag
config().delete_flag
deleteFlag
delete_flag
DeleteFlag
Operation
Rust
Node
Python
Go
Backend capabilities
backend_capabilities
backendCapabilities
backend_capabilities
BackendCapabilities
Liveness
is_live
isLive
is_live
IsLive
Readiness probe
probe
probe
probe
Probe
Metrics snapshot
metrics_snapshot
metricsSnapshot
metrics_snapshot
MetricsSnapshot
Prometheus text
render_prometheus
renderPrometheus
render_prometheus
RenderPrometheus
Scheduler loop
run_scheduler
(interval)
(interval)
(interval)
Maintenance sweep
maintain
maintain
maintain
Maintain
These functions need no initialized client and add no transport or deployment behavior. See Integrations for their bounded profile and recipes.
Operation
Rust
Node
Python
Go
Encode CloudEvents 1.0 structured JSON
CloudEvent::encode, encode_cloud_event
encodeCloudEvent
encode_cloud_event
EncodeCloudEvent
Decode CloudEvents 1.0 structured JSON
CloudEvent::decode, decode_cloud_event
decodeCloudEvent
decode_cloud_event
DecodeCloudEvent
Import explicit environment aliases
import_env_config
importEnvConfig
import_env_config
ImportEnvConfig
Export canonical environment names
export_env_config
exportEnvConfig
export_env_config
ExportEnvConfig
Use raw methods for bytes and exact cross-language contracts. Use handles when the
payload is app JSON and you want the name, codec, and type to stay together.
type SendEmail = { to : string ; template : string };
const emails = forge . queue < SendEmail > ( " emails " );
await emails . enqueue ({ to: " a@b.c " , template: " welcome " });
const profile = forge . kv <{ name : string }> ( " user:42:profile " );
await profile . set ({ name: " Ada " });
const events = forge . topic <{ type : " created " ; userId : string }> ( " user.created " );
await events . publish ({ type: " created " , userId: " 42 " });
emails = forge. queue ( " emails " )
await emails. enqueue ( { " to " : " a@b.c " , " template " : " welcome " } )
profile = forge. kv ( " user:42:profile " )
await profile. set ( { " name " : " Ada " } )
events = forge. topic ( " user.created " )
await events. publish ( { " type " : " created " , " user_id " : " 42 " } )
use forgelib :: {KvKey, KvTyped, QueuePayload, QueueTyped, QueueName, SetOpts};
#[derive(Serialize, Deserialize)]
struct SendEmail { to : String, template : String }
impl QueuePayload for SendEmail {
const QUEUE : QueueName< Self > = QueueName :: new ( " emails " );
let profile_key = KvKey :: <Profile> :: new ( " user:42:profile " );
forge . queue () . enqueue_typed ( & email ) . await ? ;
forge . kv () . set_typed ( & profile_key , & profile , SetOpts :: new ()) . await ? ;
A few methods return small records. The field names match the table; Node uses
camelCase and times end in Ms.
Decision (rate limit): allowed, limit, remaining, resetAfterSeconds, retryAfterSeconds.
Job (queue): id, receipt, payload, attempt, maxAttempts, plus the queue and lease deadline.
QueueDepth : visible, inFlight, delayed.
BlobInfo (head): key, size, contentType, etag, lastModified, metadata.
BlobSummary (list): key, size, opaque etag, lastModified; use head for content type and user metadata.
ProxyPresign : url, method, key, expiresEpoch, maxBytes, signature, requiredHeaders.
NativePresign : url, method, expiresEpoch, requiredHeaders, constraints; native PUT has no portable size ceiling.
Session : userId, createdAt, expiresAt.
ApiKey (on create): id, secret (shown once), label, createdAt, optional expiresAt, scopes, metadata.
TokenConsumption : userId, bounded opaque payload; returned atomically once.
BackendInfo : primitive, provider, durable, caveats.
Every failure maps onto one of these. The retryable column says whether trying again
might succeed.
Error
Retryable
Meaning
Config
no
Bad configuration. Only happens during init().
Unavailable
yes
A transient backend outage (timeout, dropped connection).
NotFound
no
The requested entity doesn’t exist.
Precondition
no
A condition failed: a CAS mismatch, a lost lease, an unknown receipt. Re-read state and decide. (A duplicate dedup_id is not an error — enqueue returns the existing job’s id.)
Limit
no
A size or quota limit was exceeded.
Invalid
no
A bad argument or malformed input.
Backend
sometimes
Anything else, carrying its own retryable flag.
In Rust these are variants of ForgeError with code(), is_retryable(), operation(), backend_id(), and a retained source chain. Node throws a structured ForgeError with code, retryable, operation, backend, safeMessage, and the normal message. Python raises typed subclasses of forgelib.ForgeError with the same fields. Go returns *forge.Error with the same stable metadata and an unwrapped local cause.
Oversized input is rejected with a Limit error rather than truncated.
Thing
Limit
Key/value key
512 bytes
Key/value value
1 MiB
Queue payload
256 KiB
Blob object
50 MiB
Blob key
1024 bytes
Pub/sub payload
~7 KB, UTF-8
Config value
64 KiB
Password input
4096 bytes
Token purpose
255 bytes
Forge ships memory and PostgreSQL for every primitive, plus filesystem and S3-compatible storage for blob bytes. Rust may inject a custom primitive trait at compile time as an advanced extension. Other languages intentionally have no plugin loader or arbitrary backend injection.
let forge = forgelib :: Forge :: builder ()
. kv ( my_redis_kv ) // kv runs on your backend; the rest stay on Postgres
Forge’s API isn’t in any model’s training data, so a coding agent won’t know it
cold. Install the companion skill and the agent learns which primitive fits which
task and the idioms for each language before it writes Forge code.
npx skills add isala404/forge