Scry is the consumer product: Remember everything. It helps people learn and memorize anything through a quiz-driven review loop. This repository contains Scry's Rust engine, not a separate product category or a generic agent-memory store.
The product has five faces over one capability system:
- PWA — the primary, phone-first human surface
- CLI — direct operator and power-user access
- skill — a product-facing agent workflow
- MCP — typed tools for agents and applications
- API — the service boundary used by the PWA and other clients
Beta access is invite-gated with a visible waitlist. Human sign-in uses magic links only; there is no OAuth path. Machine faces use operator-gated service sessions. Subscription is the intended business model. Public signup remains closed until generation costs are bounded and privacy, reliability, and Stripe billing are proven. Fast and smooth are product bars: p95 acknowledgement below 100 ms, p95 graded-visible feedback below 300 ms, and first quiz visible below 20 s. See VISION.md for the canonical product contract.
Scry keeps a pure Rust learning kernel and explicit boundary crates. The kernel owns deterministic scheduling, grading, progression, queue selection, and learning invariants. Boundary crates own persistence, generation, sessions, identity, API routes, rendering, deployment, and QA.
The current production proof surface is the native Rust memory-engine-api
process on Misty Step's isolated DigitalOcean public application host, backed
by Neon Postgres and served at https://scry.study. Deployment, environment,
auth, storage, rollback, and smoke-test details live in
docs/runbook.md.
- Canonical learning-domain types
- FSRS state transitions
- Deterministic grading
- Progression and queue primitives
- Recitation grading
- Async rubric grading contracts
- Vendor-neutral rubric adapter interfaces
- Fixture corpora for contract and interface tests
- Evals and benchmarks for learning-behavior regressions
- Experimental clients that consume the API outside the reusable kernel
The core runtime in crates/memory-engine-core stays framework-free: no
filesystem, network, UI, logging, model clients, or persistence. Service,
storage, UI, auth, content parsing, and deployment experiments live in dedicated
boundary crates until dogfood evidence proves a stable reusable contract.
The Rust migration is complete for the main runtime:
- canonical types
- FSRS scheduler wrapper
- deterministic grader
- progression metadata and eligibility helpers
- queue candidate filtering and selection
- deterministic recitation grading
- async rubric grading surface
- facade adapter/testkit modules
- service, persistence, generation, study, and local HTTP app hosts
- Rust QA and benchmark receipt runners
The sole current production dogfood surface is the native
memory-engine-api process on the isolated public application host, backed by
Neon Postgres and served at https://scry.study. Agent-facing deployment,
environment, auth, storage, rollback, and smoke-test details live in
docs/runbook.md.
Current strategy and verification docs:
Historical extraction packets, retained as boundary evidence rather than active delivery oracles:
- SLICE-1-KERNEL.md
- SLICE-2-PROGRESSION.md
- SLICE-3-RUBRIC.md
- SLICE-4-SERVICE-PROTOTYPE.md
- exemplars.md
The active GitHub Issues queue tracks Scry production dogfood usefulness, service hardening, learning-science quality, input capture, and capability-boundary work on top of the Rust stack.
Rust consumers should use the facade crate:
use memory_engine::{next, ExactPrompt, ExactPromptKind, GradeContext, Grader, Prompt, ReviewUnitId};
let prompt = Prompt::Exact(ExactPrompt {
kind: ExactPromptKind::ShortAnswer,
review_unit_id: ReviewUnitId::new("latin-1"),
prompt: "Translate poena".to_owned(),
accepted_answers: vec!["punishment".to_owned()],
equivalence_groups: Vec::new(),
ignored_tokens: Vec::new(),
});
let grade = Grader::new().grade(
&prompt,
"Punishment",
GradeContext {
response_time_ms: 3_200,
prior_reps: 3,
},
);
let next_state = next(None, grade.rating, 1_779_465_600_000).expect("schedule");Rubric grading stays adapter-backed; the Rust core owns normalization and dispatch, while callers own any model client:
use memory_engine::{
AsyncGrader, GradeContext, GradeablePrompt, RubricAssessment, RubricCriterion,
RubricCriterionResult, RubricCriterionVerdict, RubricDefinition, RubricPrompt,
ReviewUnitId, StaticRubricGrader,
};
let prompt = RubricPrompt {
review_unit_id: ReviewUnitId::new("rubric-1"),
prompt: "Continue the prayer.".to_owned(),
rubric: RubricDefinition {
answer_guide: vec!["Continue with the next line.".to_owned()],
passing_score: 1,
criteria: vec![RubricCriterion {
name: "continuation".to_owned(),
description: "Gives the next line.".to_owned(),
required: true,
}],
},
};
let grader = AsyncGrader::with_rubric_grader(StaticRubricGrader::new(RubricAssessment {
model: Some("fixture".to_owned()),
confidence: 1.0,
feedback: "Strong answer.".to_owned(),
criterion_results: vec![RubricCriterionResult {
name: "continuation".to_owned(),
verdict: RubricCriterionVerdict::Pass,
evidence: "Supplied the continuation.".to_owned(),
}],
}));
let grade = grader.grade_prompt(
GradeablePrompt::Rubric(&prompt),
"Strong answer.",
GradeContext {
response_time_ms: 6_000,
prior_reps: 0,
},
).expect("rubric grade");Test fixtures for contract and interface tests:
use memory_engine::testkit::{grading_fixtures, scheduler_fixtures};Prerequisites: the pinned Rust toolchain from rust-toolchain.toml and Bun for
the fast gate. Dagger is required for the full/ship parity handoff; it uses the
same Rust 1.94 line through the Dagger image.
Set the repository hook and run the local Rust verification loop:
git config core.hooksPath .githooks
cargo fmt --all --check
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo doc --workspace --no-deps
bun run ci
bun run ci:local # compatibility alias for bun run ciRun the Dagger-backed full gate before handoff:
bun run ci:fullRun the production-shaped API locally with a file store:
MEMORY_ENGINE_ENVIRONMENT=development MEMORY_ENGINE_ENABLE_FILE_STORE=true MEMORY_ENGINE_API_STORE_DIR=.tmp/api-dev MEMORY_ENGINE_AUTH_ALLOWED_EMAILS=owner@example.com MEMORY_ENGINE_RETURN_UNSUBSCRIBE_SECRET=local-dev-secret MEMORY_ENGINE_AUTH_LINK_OUTBOX_PATH=.tmp/api-dev/outbox.tsv HOST=127.0.0.1 PORT=18080 cargo run -p memory-engine-apiFrom another shell, verify the local health route:
curl -fsS http://127.0.0.1:18080/healthzMIT