Search by

sugarcraft / candy-kv

detain

PHP port of charmbracelet/skate — a personal key/value store with multi-database support, binary data, and glob/list filtering.

Package info

github.com/sugarcraft/candy-kv

pkg:composer/sugarcraft/candy-kv

Statistics

Installs: 0

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

dev-master 2026-10-17 07:19 UTC

This package is auto-updated.

Last update: 2026-10-17 07:24:19 UTC


README

candy-kv

CI codecov Packagist Version License PHP

CandyKv

Formerly published as sugarcraft/sugar-skate (renamed 2026-10). Namespace changed: SugarCraft\Skate\ → SugarCraft\Kv\.

candy-kv — a personal key/value store for PHP 8.3+ with multi-database support, binary data handling, and glob/list filtering.

Features

  • Multi-database — separate stores with @dbname suffix, auto-created on first use
  • Binary data — safely stores and retrieves raw binary (images, files) via base64 encoding
  • Glob pattern matching — list/get/delete keys using * and ? wildcards
  • Ordered listing — forward or reverse lexicographic order
  • Flexible listing — keys only, values only, or key-value pairs
  • SQLite-backed — one SQLite DB per database, stored in $XDG_CONFIG_HOME/skate/ or ~/.config/skate/
  • PHP 8.3+ — pure PHP, no extension required beyond SQLite (php-sqlite3)
  • Iterable streams — list() yields results without loading everything into memory
  • TTL / expiry — set keys that automatically expire after a given number of seconds
  • Levenshtein suggestions — typo suggestions on key miss (get command prints to stderr)
  • Import/Export — bulk load or save entries in JSON or YAML format, with optional atomic transaction
  • Atomic transactions — Database::transaction() wraps a callback in BEGIN/COMMIT/ROLLBACK

Install

composer require sugarcraft/candy-kv

Quick Start

use SugarCraft\Kv\Store;

$store = new Store();

// Set and get
$store->set('greeting', 'Hello, World!');
echo $store->get('greeting'); // Hello, World!

// With a database — target it with the `key@db` suffix.
// (set()'s 3rd parameter is `bool $binary`, get()'s is a fallback string —
// a db name NEVER goes there; the suffix is the only routing mechanism.)
$store->set('token@passwords', 'ghp_xxxx');
echo $store->get('token@passwords');

// List all keys
foreach ($store->list() as $entry) {
    echo "{$entry->key} => {$entry->value}\n";
}

// Glob patterns
foreach ($store->list(pattern: 'user-*') as $entry) { ... }

// Delete
$store->delete('greeting');

CLI

candy-kv set <key> [value] [--ttl=SECONDS]          # Set a key (reads stdin if no value)
candy-kv get <key>                                # Get a value (suggests typo on miss)
candy-kv list [-k|-v] [-r] [-d delim] [pattern]   # List entries
candy-kv delete <key>                              # Delete a key (glob patterns supported)
candy-kv list-dbs                                   # Show all databases
candy-kv import <json|yaml> <path> [--no-atomic]   # Import entries (path=- for STDIN)
candy-kv export <json|yaml> [db] [pattern]         # Export entries

TTL (Time-To-Live)

Use --ttl to set keys that automatically expire:

candy-kv set session:abc123 '{"user":"bob"}' --ttl=3600  # expires in 1 hour

STDIN

When no value is given as an argument, set reads from stdin. For import, use - or /dev/stdin as the path:

echo "my-secret-token" | candy-kv set api-token
candy-kv import json - < backup.json

Note: piped values are stored verbatim — the full stdin is read with no trimming, byte-for-byte. echo therefore stores its trailing newline; use printf '%s' token | (or pass the value as an argument) when you need the exact bytes without it.

Import / Export

Import and export support JSON and YAML formats. Import runs inside an atomic transaction by default; pass --no-atomic to disable:

candy-kv import json backup.json
candy-kv import yaml -             # read from STDIN
candy-kv export json > dump.json
candy-kv export yaml mydb 'user-*'  # export filtered keys from a specific database

The export output includes remaining TTL as a _ttl top-level key in JSON, or skate_ttl_<key> entries in YAML.

Data Directory

Default: ~/.config/skate/ (respects $XDG_CONFIG_HOME).

Each database gets its own SQLite file: ~/.config/skate/<dbname>.db.

Demos

Glob pattern matching

glob

Shared foundations

candy-kv uses sugar-fuzzy for Smith-Waterman scored matching infrastructure. The matcher is wired for future fuzzy key search; glob-to-SQLIKE pattern filtering remains the active filter path today.

License

MIT

Credits & inspiration

Originally inspired by the Go Charm ecosystem; SugarCraft is developed as a native PHP project.