Shakti — Physical Discipline and Movement Intelligence Platform
This document specifies what is implemented in libs/shakti/*. Shakti is a
pure library domain: 28 Nx library projects, no apps/shakti and no
services/shakti. Every library is a self-contained TypeScript package with an
empty dependencies map — there are no runtime npm dependencies and no
cross-domain imports anywhere in libs/shakti/. @shakti/core is the only
library other Shakti libraries would build on; in the current source even that
coupling is not yet wired (libraries re-declare their own local types).
The dominant implementation pattern is a knowledge-base / configuration
registry: each source module declares typed, domain-specific records (e.g.
heart-rate zones, periodization presets, asana taxonomy, API endpoint
configurations), registers them into module-level Map stores, and exposes
getAll*(), get*ById(), search*(), count*(), and reset*Store()
accessors plus pure calculation helpers. This specification documents the parts
of that surface that are stable and load-bearing.
1. Core Foundation (@shakti/core)#
@shakti/core is the foundation library. Its barrel (src/index.ts) re-exports
five modules: types.ts, schemas.ts, db-schema.ts, events.ts, auth.ts.
Each section below documents one of these modules in detail.
1.1 Result<T, E> (types.ts)#
Shakti uses a discriminated-union outcome type for domain operations instead of throwing exceptions. This allows callers to handle domain errors without try/catch, and keeps the error handling surface explicit and type-safe.
| Member | Shape | Meaning |
|---|---|---|
Ok<T> |
{ ok: true; value: T } |
Success |
Err<E> |
{ ok: false; error: E } |
Failure |
Result<T, E = Error> |
Ok<T> | Err<E> |
Union |
Constructors and combinators: ok, err, isOk, isErr, unwrap,
unwrapOr, mapResult, mapError, flatMap, tryCatch, tryCatchAsync.
Domain error type ShaktiError carries { code, message, details? }. The
SHAKTI_ERROR_CODES constant enumerates twelve codes: INVALID_INPUT,
NOT_FOUND, UNAUTHORIZED, FORBIDDEN, CONFLICT, EXERCISE_UNSAFE,
INJURY_RESTRICTION, PROGRAM_INVALID, SESSION_EXPIRED, EQUIPMENT_MISSING,
PREREQUISITE_UNMET, OVERTRAINING_RISK. ShaktiResult<T> aliases
Result<T, ShaktiError>.
1.2 Movement and anatomy taxonomy (types.ts)#
The movement and anatomy taxonomy is the shared vocabulary used throughout the domain. Every exercise, technique, and form-analysis result references these types — they are the conceptual atoms of the Shakti type system.
| Type | Values |
|---|---|
MovementPattern |
push, pull, hinge, squat, lunge, rotate, gait, carry, brace, anti_rotation, crawl, climb, throw, strike (14) |
BodyRegion |
upper_body, lower_body, core, full_body |
UpperBodySubRegion |
chest, upper_back, lower_back, shoulders, biceps, triceps, forearms, neck, traps |
LowerBodySubRegion |
quadriceps, hamstrings, glutes, calves, hip_flexors, adductors, abductors, tibialis |
CoreSubRegion |
rectus_abdominis, obliques, transverse_abdominis, erector_spinae, pelvic_floor, diaphragm |
MuscleGroup |
76 individually-named muscles (chest, shoulders, back, arms, forearms, core, glutes, quads, hamstrings, adductors, calves, neck), exported as ALL_MUSCLE_GROUPS |
JointType |
shoulder, elbow, wrist, hip, knee, ankle, spine_cervical, spine_thoracic, spine_lumbar, sacroiliac, metacarpophalangeal, interphalangeal, temporomandibular (13) |
BODY_REGION_MAP maps each region to its sub-regions;
getBodyRegionForSubRegion resolves the reverse. JOINT_ROM_NORMS holds
normative range-of-motion data (flexion / extension and optional abduction,
adduction, rotation, lateral flexion, internal/external rotation) per joint;
getJointROM(joint) looks one up.
1.3 Training value objects (types.ts)#
Training value objects model the building blocks of how exercise is prescribed.
Rather than embedding raw numbers in workout records, these types carry semantic
meaning — a Tempo is not just four integers but a named set of eccentric,
pause, concentric, and pause phases with helpers to format and compute total
time. This prevents ambiguity when workouts are serialized, shared, or analysed.
DifficultyScale—beginner,intermediate,advanced,elite,master. Ordered viaDIFFICULTY_ORDER; compared withcompareDifficultyandisDifficultyAtLeast.IntensityLevel—low,moderate,high,very_high,maximal.getIntensityHRPercent(level)returns a heart-rate%band.Duration—{ seconds }value object withdurationFromSeconds/Minutes/Hours,durationToMinutes/Hours,formatDuration,addDurations.Tempo—{ eccentric, pauseBottom, concentric, pauseTop }. Helpers:createTempo,tempoTotalSeconds,formatTempo. SevenTEMPO_PRESETS(controlled,explosive,time_under_tension,isometric,normal,eccentric_focus,speed).RepRange—{ min, max, target }withcreateRepRangeand fiveREP_RANGE_PRESETS(strength,power,hypertrophy,muscular_endurance,endurance).SetType—straight,drop,super,giant,cluster,rest_pause,myo_rep,pyramid,reverse_pyramid,amrap,emom,tabata(12).SetConfigurationbundles{ type, sets, repRange, restBetweenSets }.RestPeriod—{ duration, mode, activity? }withRestModeofactive/passive; fiveREST_PRESETS.EquipmentCategory— 14 categories (barbell,dumbbell,kettlebell,machine,cable,band,bodyweight,cardio,yoga,martial_arts,recovery,specialty,outdoor,home).EQUIPMENT_CATALOGholds 75EquipmentItemrecords (id,name,category,portability,spaceRequired);getEquipmentByCategoryandgetPortableEquipmentfilter it.PhysicalAttributes— height, weight, optional wingspan, body-fat, resting/max HR, VO2max, measurement system. Helpers:estimateMaxHR(age)(220 − age),calculateBMI,getBMICategory.FitnessAssessment— eight scored qualities (cardiovascular, strength, flexibility, balance, power, endurance, agility, coordination).computeOverallFitnessaverages them;getFitnessLevel(score)maps a 0–100 score to aDifficultyScale.InjuryStatus—{ id, bodyPart, severity, phase, description, dateReported, restrictions }.InjurySeverity∈ {minor,moderate,severe,critical};InjuryPhase∈ {acute,subacute,chronic,rehabilitation,return_to_sport}.MovementRestriction—RestrictionType∈ {avoid,reduce_load,reduce_rom,modify_tempo,use_alternative}, with affected patterns / joints and optional load/ROM caps.isExerciseSafe(patterns, joints, restrictions)returns whether an exercise clears theavoidrestrictions.EnergySystem—phosphagen,glycolytic,oxidative.ENERGY_SYSTEMSdocuments duration and intensity ranges;dominantEnergySystem(durationSeconds)selects one.TrainingGoal— 20 goal values, exported asALL_TRAINING_GOALS.Laterality—unilateral,bilateral,alternating,ipsilateral,contralateral.PlaneOfMotion—sagittal,frontal,transverse,multiplanar(withPLANE_DESCRIPTIONS).ForceVector— six values withFORCE_VECTOR_EXAMPLES.LoadType—absolute,relative,bodyweight_percentage,rpe,rir,percentage_1rm.LoadPrescriptionbuilders:createAbsoluteLoad,createRelativeLoad,createRPELoad(validates 1–10),createRIRLoad.rpeToRIR/rirToRPEconvert between RPE and reps-in-reserve.ProgressionModelType—linear,undulating,block,conjugate,step_loading,autoregulated.PROGRESSION_PRESETSprovides aProgressionModelper type with weekly increment, deload frequency, and deload percentage.
1.4 Validation schemas (schemas.ts)#
schemas.ts defines TypeScript interfaces plus hand-written validate*
functions that return readonly string[] of error messages (empty = valid).
Validation is plain TypeScript — there is no Zod, Yup, or Joi in this
domain.
The foundational enums define the platform's disciplinary vocabulary. These values appear throughout the rest of the codebase — in technique records, session logs, program schemas, and the database schema — so knowing them is essential context:
| Type | Values (count) |
|---|---|
Discipline |
yoga, martial_arts, strength_training, combat_sports, calisthenics, cardio, mobility, dance, pilates, crossfit, functional_training, olympic_weightlifting, powerlifting, strongman, gymnastics, swimming, running, cycling, rowing, climbing (20) — exported as ALL_DISCIPLINES |
YogaStyle |
hatha, vinyasa, ashtanga, iyengar, bikram, yin, restorative, kundalini, power, jivamukti, anusara, sivananda, forrest, rocket, aerial (15) |
MartialArtStyle |
28 styles (BJJ, judo, three karate variants, two taekwondo variants, Muay Thai, boxing, kickboxing, wing chun, aikido, krav maga, hapkido, capoeira, sambo, three wrestling variants, two kung fu variants, tai chi, MMA, kendo, fencing, savate, lethwei, sanda, pencak silat) |
DifficultyLevel |
beginner, intermediate, advanced, elite, master |
MeasurementSystem |
metric, imperial |
Gender |
male, female, non_binary, prefer_not_to_say |
The schema interfaces and their validation functions cover the complete data
surface of the platform. Each interface has a paired validate* function that
returns an array of error strings — an empty array means the record is valid:
TechniqueSchema/validateTechnique— id, name, discipline, optional style, difficulty, description, instruction steps, common mistakes, target + synergy muscles, optional breathing pattern, contraindications, prerequisites, media URLs.ExerciseSchema/validateExercise—ExerciseCategory∈ {compound,isolation,plyometric,isometric,ballistic,flexibility,balance,cardio,core,corrective}; movement patterns, planes, primary/secondary/stabilizer muscles, joints, required/optional equipment, laterality, force vector, instructions, cues, common mistakes, regressions, progressions, alternatives, contraindications, media.WorkoutSchema+WorkoutBlockSchema+WorkoutExerciseSchema/validateWorkout—WorkoutTypehas 16 values (strength,hypertrophy,endurance,hiit,circuit,yoga_flow,martial_arts_drill,sparring,technique,mobility,recovery,sport_specific,competition,assessment,warmup,cooldown). A workout has an optional warmup block, one-or-more main blocks, and an optional cooldown block.ProgramSchema+ProgramPhaseSchema/validateProgram—ProgramGoal(10 values),PeriodizationType∈ {linear,undulating,block,conjugate,concurrent,reverse_linear}; duration weeks, days per week (1–7), and one-or-more phases each with a week range, focus, intensity range, volume multiplier, deload flag, and workout IDs.SessionSchema+SessionExerciseData+SessionSetData/validateSession—SessionStatus∈ {planned,in_progress,completed,paused,skipped,cancelled}. A session records practitioner, optional workout/program, discipline, type, start/end times, planned/actual duration, per-exercise set data, totals (volume, sets, reps), optional calories, heart rates, perceived exertion (1–10), mood (1–10), and energy level.PractitionerSchema/validatePractitioner— user id, display name, optional demographics, measurement system, disciplines, goals, fitness level, experience years, available equipment, available days/week, session duration preference, injuries, restrictions, timezone, timestamps.BeltRankSchema/validateBeltRank—BeltColor∈ {white,yellow,orange,green,blue,purple,brown,red,black,coral,red_white}; style, optional degree, order, minimum time in months, requirements.AchievementSchema+AchievementCondition/validateAchievement—AchievementCategory(10 values),AchievementRarity∈ {common,uncommon,rare,epic,legendary}; xp reward, one-or-more conditions (metric / operator / value), secret flag.ChallengeSchema/validateChallenge—ChallengeType∈ {streak,volume,consistency,skill,competition,team,seasonal}; duration, date window, target value/metric, optional participant cap, rewards, rules.InstructorSchema+CertificationSchema/validateInstructor— bio, disciplines, styles, certifications, years of experience, specializations, rating (0–5), student/class counts, verification flag, languages.ClassSchema/validateClass—ClassFormat∈ {in_person,virtual,hybrid,on_demand}; instructor, discipline, difficulty, duration, capacity, enrollment, scheduled time, optional recurrence, location, virtual meeting URL, equipment, price/currency.GoalSchema+GoalMilestoneSchema/validateGoal— title, target / current value, unit, optional deadline, milestones, completion flag.
schemas.ts also provides standalone calculation helpers that derive numeric
results from schema data: checkEquipmentAvailability, calculateVolume,
calculateOneRepMax (Brzycki formula w · 36/(37−reps)),
calculateWeightForReps, calculateTotalSessionVolume,
calculateSessionDensity, calculateFormScore, calculateTrainingAge.
1.5 Authorization (auth.ts)#
Role-based access control is implemented as static permission tables evaluated at call time. There is no middleware framework or runtime token-signing — this module is pure logic that any application layer can call to enforce access rules.
ShaktiRole—practitioner,instructor,studio_owner,admin,moderator,content_creator,guest.ROLE_HIERARCHYassigns numeric ranks (guest 0 → admin 100);isRoleAtLeast/compareRolesorder them.ResourceType— 16 resources (exercise,technique,workout,program,session,practitioner_profile,class,achievement,challenge,instructor_profile,studio,certification,belt_rank,comment,media,analytics).Action—create,read,update,delete,publish,enroll,manage.Permission—{ resource, action, scope }withscope∈ {own,assigned,all}.PermissionKeyis the templated string`${resource}:${action}:${scope}`.- Per-role permission arrays are defined for all seven roles;
getPermissionsForRole(role)returns them. checkPermission(ctx, resource, action, resourceOwnerId?)evaluates anAuthContextagainst the permission set, checkingallthenownthenassignedscope, and returns anAuthorizationResult({ allowed, reason?, matchedPermission? }).- Token helpers:
TokenClaims,isTokenExpired,getTokenRemainingSeconds,tokenClaimsToAuthContext. API-key helpers:ApiKeyConfig,validateApiKeyAccess(checks expiry, allowed resources, then permission).
This is a pure authorization-logic library; it performs no token signing, network calls, or session storage.
2. Discipline Domain Objects#
Each discipline library is a knowledge base of typed records. The common pattern
across all five disciplines is: typed record interfaces declared locally,
records registered into module-level Map stores at module initialization, and
getAll* / get*ById / search* accessors exported for querying. Field and
enum definitions are local to each module — they share no cross-library imports.
2.1 @shakti/yoga#
Six modules (asanas, pranayama, sequences, styles, meditation,
ayurveda). Asana taxonomy includes AsanaCategory (11 values: standing,
seated, prone, supine, inversion, balance, twist, backbend, forward fold, arm
balance, hip opener), and yoga-specific concepts modelled as types:
Chakra— 7 energy centresDosha—vata/pitta/kapha(Ayurvedic constitutions)Drishti— 8 traditional gaze points used during asana practiceBandha—mula,uddiyana,jalandhara,maha(energy locks)PropType— 9 supported yoga props (blocks, straps, bolsters, etc.)EngagementLevel—primary,secondary,stabilizer,stretched
pranayama covers breathwork techniques; sequences covers sequence
construction; ayurveda covers dosha-based personalization.
2.2 @shakti/strength#
Eight modules: exercises, compounds, olympic, calisthenics, programs,
powerlifting, hypertrophy, programs. programs.ts ships 15 complete
program templates plus 5 deload protocols spanning linear progression,
undulating, block, and conjugate periodization. These are fully specified
multi-week templates — not just parameter ranges, but complete program
structures with phases, loading schemes, and deload triggers.
2.3 @shakti/martial-arts#
Eight modules: techniques, striking, grappling, mma, traditional,
weapons, ranks, sparring.
weapons.tscovers bo staff, nunchaku, sword, kendo, kali, and HEMA (Historical European Martial Arts)ranks.tscovers belt/rank progression across multiple martial art stylessparring.tscovers sparring and competition formats with scoring and matchmaking
2.4 @shakti/combat-sports#
Five modules: boxing, kickboxing, muay-thai, wrestling, mma-training.
Boxing alone covers stances, footwork, shadowboxing, bag and pad work,
conditioning, rulesets, training camps, and weight-cutting protocols — showing
the depth of coverage: each module models the full sport preparation lifecycle,
not just a technique list.
2.5 @shakti/mobility#
Six modules: stretching, joint-mobility, smr (self-myofascial release),
recovery, injury-prevention, rehabilitation. The rehabilitation module
includes graduated return-to-training protocols with clearance checkpoints,
making the library useful for practitioners coming back from injury as well as
healthy practitioners maintaining movement quality.
3. Intelligence Libraries#
The intelligence libraries work across all disciplines. They consume the shared
anatomy taxonomy and exercise vocabulary from @shakti/core (and from their own
local type re-declarations) to provide analysis, adaptation, and advanced
feature modules that are not tied to any single discipline.
3.1 @shakti/biometrics#
Five modules: heart-rate, hrv (within heart-rate), body-composition,
performance-metrics, recovery-metrics, device-integrations.
heart-rate.ts exposes the following types and calculators:
- Types:
HRZoneNumber(1–5),MaxHRMethod,HRVMetric(rmssd,sdnn,pnn50,lf_hf_ratio,ln_rmssd,hrv_score),ThresholdType,CardiacDriftCategory,RecoverySpeed. - Record types:
HeartRateZone,MaxHRFormula,HRVAnalysisConfig,RestingHRBenchmark,CardiacDriftConfig,HRRecoveryBenchmark,ThresholdEstimation,HRTrackingConfig. - Calculations:
calculateMaxHR,calculateHRR,calculateTargetHR. - Registry accessors:
getAll*,get*,searchHeartRate,getHeartRateCount,resetHeartRateStore.
device-integrations.ts provides a catalog of named wearable and sensor
integrations as descriptive configuration records — not live SDK clients. Each
record documents how to connect and what data the platform provides, so
application code can use the catalog to guide integration implementation:
- Types:
PlatformType,ConnectionType(bluetooth_le,ant_plus,wifi,usb,api_rest,api_oauth2,nfc),DeviceCategory(10),DataType(15),SyncFrequency. - Documented platforms: Apple HealthKit, Google Health Connect, Samsung Health SDK, Garmin Connect, Whoop 4.0, Oura Ring Gen3, Fitbit, Polar Vantage V3, COROS PACE 3, Wahoo TICKR, Stages power meters, the Bluetooth GATT services (Heart Rate, Cycling Power, Cycling/Running Speed and Cadence), ANT+ profiles, Tonal, and PUSH Band 2.0. Each record carries prose-level setup and rate-limit metadata.
3.2 @shakti/form-analysis#
Five modules: motion-capture, form-scoring, technique-analysis,
real-time-feedback, video-analysis.
form-scoring.ts is the domain's fault taxonomy and scoring knowledge base. It
defines:
FormCategory— 10 exercise categories, each with different evaluation criteriaDeviationType— 14 fault patterns:knee_valgus,butt_wink,forward_lean,bar_drift,lockout_incomplete,elbow_flare, and 8 othersSeverityLevel— fault severity on a graded scaleScoreGrade— letter gradesAthroughFrolled up from severity scores
motion-capture.ts documents pose-estimation approaches (MediaPipe /
TensorFlow.js are referenced as descriptive options). All pose math is
self-contained — there is no @aja dependency in this library.
3.3 @shakti/personalization#
Five modules: practitioner-profiling, adaptive-programming,
ai-workout-generation, recommendation-engine, goal-management. Together
these modules model the full lifecycle of a personalized training relationship —
from initial profiling through adaptive adjustments to goal tracking.
3.4 @shakti/gamification#
Six modules: achievement-system, streak-system, xp-leveling, challenges,
leaderboards, rewards-virtual-items. The gamification library is designed to
listen to domain events rather than be called directly from session-logging code
— this keeps the two concerns decoupled and ensures gamification enrichment adds
no latency to the core training flow.
3.5 @shakti/sota-critical#
@shakti/sota-critical contains 16 modules. These modules represent
production-near capabilities that need special hardware or research-grade data
sources, and so are kept separate from the main platform to allow independent
deployment and validation:
mental-health-mood,readiness-scheduling,velocity-based-trainingdynamic-sequence-generation,virtual-world-gamification,longevity-healthspangenetic-biomarker,vr-fitness,smart-gym-intelligence,health-ai-coachadvanced-social-live,edge-ai-offline,voice-first-handsfreedata-privacy-control,enterprise-b2b,v2-combat-style-classifier
voice-first-handsfree.ts is the canonical home of the Hey Shakti wake-word
phrase definition. The V2 combat-style classifier module is described in detail
in §5.4.
3.6 @shakti/sota-advanced#
@shakti/sota-advanced contains 10 modules for differentiating next-generation
capabilities that sit further along the research-to-production spectrum than
sota-critical:
accessibility-inclusion,advanced-equipment-integrationadvanced-motion-analysis,ai-coach-personal-trainerglobal-cultural-features,nutrition-holistic-healthpredictive-analytics,research-science-integrationsocial-competitive-features,wearable-deep-integration
3.7 Operations, delivery, and platform libraries#
The remaining libraries handle the operational and delivery surfaces of the
platform. Each follows the same knowledge-base pattern: typed records, Map
stores, and getAll* accessors. Module counts are listed for orientation:
@shakti/community— 5 modules: social profiles/feed, training groups, accountability partners, messaging@shakti/audio— 3 modules: audio content, music integration, voice commands@shakti/video— 4 modules: content management, follow-along workouts, live streaming, instructional library@shakti/visualization— 5 modules: movement/anatomy visualization, AR, VR, avatar@shakti/studio— 5 modules: class/equipment/facility/membership/staff management@shakti/events— 5 modules: calendar, class scheduling, competitions, live class delivery, workshops@shakti/certifications— 4 modules: credential management, continuing education, licensing/insurance, the Shakti certification program@shakti/instructor-sdk— 5 modules: assessment tools, business analytics, client management, content creation, program builder@shakti/sdk— 3 modules: SDK core, resources, utilities@shakti/web— 6 portal page-spec modules@shakti/mobile— 7 mobile feature-spec modules@shakti/testing— 5 modules: unit, integration, e2e, performance, security testing utilities@shakti/documentation— 3 documentation-spec modules@shakti/deployment— 5 modules: CI/CD, containerization, GPU/ML infrastructure, infrastructure setup, monitoring/observability
4. API Configuration Layer (@shakti/api)#
@shakti/api is not a running HTTP server and not a per-resource REST
contract. It is a configuration-and-metadata registry: each module declares
typed configuration records describing API building blocks and registers them
into Map stores. It exposes getAll*() accessors over those records. There
are no /api/v1/users, /api/v1/workouts/{id}-style per-resource routes in the
source.
The purpose of this library is to give applications and integrators a machine-readable description of the API surface they will build — endpoint behaviours, auth strategies, rate-limit tiers, error-handling patterns — without coupling to any specific HTTP framework.
Six modules (re-exported from src/index.ts):
core-api.ts— declares ten record categories: 7 genericRestEndpointconfigs, 7GraphQLSchemaconfigs, 7AuthMiddlewareconfigs, 7RateLimittier configs, 7ApiVersionconfigs, 7ValidationSchemaconfigs, 7ErrorHandlerconfigs, 7ApiDocconfigs, 7CorsConfigconfigs, 6ApiMonitorconfigs. The sevenRestEndpointrecords use generic paths (/api/v1/resources,/api/v1/resources/:id,/api/v1/search,/api/v1/batch) and carryhttpMethod,authRequired,rateLimitPerMinute,responseFormat,cacheDuration, andendpointType∈ {resource-listing,resource-detail,resource-create,resource-update,resource-delete,search,batch-operation}.exercise-workout-endpoints.ts— endpoint configuration records for exercise listing/detail/search, workout listing/creation/update, AI workout generation, and program listing/enrollment. Records carry behavioural fields (e.g.WorkoutCreationhascreationMethod,maxExercises,templateBased,validationStrict,draftSupport,collaborativeEditing) — not literal URL paths.session-tracking-endpoints.ts— configs for session start/update, exercise logging, session completion, history, and progress summaries.social-community-endpoints.ts— configs for activity feeds, posts, likes, comments, user profiles, follow systems.instructor-business-endpoints.ts— configs for client lists, program assignment, class schedules/creation, business analytics, content uploads.form-analysis-endpoints.ts— configs for video upload, analysis status/results, real-time analysis, WebSocket feedback, analysis history.
Consumers query this registry to understand intended API shape; an actual HTTP server would be built in a separate application.
5. Fighting-Ruleset Bridge#
@shakti/fighting-ruleset-bridge is a fully-implemented, deterministic
transform library. It takes real combat-sport biomechanics measurements and
converts them into fighting-game frame data appropriate for a specific ruleset.
The bridge's barrel re-exports fighting-ruleset-bridge.ts and
profiles/launch-profiles.ts.
5.1 Constants and identifiers#
Three constants anchor the bridge's identity and versioning:
SHAKTI_FIGHTING_RULESET_BRIDGE_PACKAGE_NAME = '@shakti/fighting-ruleset-bridge'SHAKTI_FIGHTING_RULESET_BRIDGE_SCHEMA_VERSION = 1SHAKTI_RULESET_IDS = ['mk', 'sf', 'tekken', 'wwe', 'ufc', 'sc', 'dj']→ShaktiRulesetId
5.2 ShaktiRulesetProfile#
A ruleset profile is the key configuration object: it maps real-sport reference numerics onto the game-feel constants that a specific fighting game demands. Each of the seven launch profiles holds a distinct set of scaling factors and rule flags corresponding to that game's design language.
| Field | Type | Meaning |
|---|---|---|
rulesetId |
ShaktiRulesetId |
Which ruleset |
displayName |
string |
Human-readable name |
tickRate |
number |
Game tick (60 in all launch profiles) |
startupScale |
number |
Multiplier on real-sport startup frames |
recoveryScale |
number |
Multiplier on real-sport recovery frames |
activeFrames |
ShaktiActiveFrameModel |
real, extended, or compressed |
reachScale |
number |
Multiplier on real-sport reach |
meterModel |
ShaktiMeterModel |
super-bar, drive, heat, rage, soul-charge, fatal-blow, blazin |
staminaModel |
ShaktiStaminaModel |
none, ufc-cardiac, wwe-exhaustion, dj-rush |
damageScaling |
ShaktiRulesetDamageScaling |
{ juggle, combo, counterHit } multipliers |
ringOut |
boolean |
Ring-out enabled |
weightDetection |
boolean |
Weight-class detection enabled |
pinSubmissionMiniGame |
boolean |
Pin/submission mini-game enabled |
environmentalFinishers |
boolean |
Environmental finishers enabled |
guardImpact |
ShaktiGuardImpactModel |
parry, guard-impact, drive-impact, none |
profiles/launch-profiles.ts exports the seven launch profiles
(SHAKTI_MK_RULESET_PROFILE, SHAKTI_SF_RULESET_PROFILE, …) and the
SHAKTI_LAUNCH_RULESET_PROFILES array. getAllShaktiRulesetProfiles() returns
them; getShaktiRulesetProfile(id) looks one up (throwing
ShaktiRulesetBridgeError for an unknown id).
5.3 Move biomechanics → frame data#
The bridge's core operation is a three-step pipeline:
-
Describe the real-sport antecedent. A
ShaktiMoveBiomechanicsInputrecord captures everything known about a move's real-world origin:moveId,fighterId,rulesetId, optionalgameOnlyflag,sourceSport(ShaktiCombatSport:boxing,kickboxing,muay-thai,wrestling,mma,bjj,karate,taekwondo,weapon-forms,game-only),shaktiTechnique,energyClass(light/medium/heavy/super),rangeClass(point-blank/close/mid/far/weapon), the three real durations (realStartupMs,realActiveMs,realRecoveryMs),forceNewtons,reachMeters, and optionalrotationDegrees,balanceCost,staminaCost,cancelComplexity,notes,tags. -
Validate and stamp a reference card.
buildShaktiMoveReferenceCard(input)returns aShaktiMoveReferenceCardafter enforcing the authoring rule viavalidateBiomechanicsInput: non-game-only moves must supply a realsourceSportandshaktiTechnique; the five numeric duration/force/reach fields must be positive and finite. The reference-card id is the caller's id or a stable SHA-256 hash of fighter/move/ruleset/sport/technique. -
Transform to frame data.
transformBiomechanicsToFrameData(input)returns aShaktiRulesetFrameDataRowby deterministically converting real durations to frames (tickRate-scaled), applying the ruleset profile's startup/recovery scales and active-frame model, computing hitstop, reach in Unreal units, damage, and on-hit / on-block advantage from force, energy class, range class, and the profile's damage-scaling and guard-impact settings.transformBiomechanicsCatalogToFrameData(inputs)maps over a catalog.
5.4 V2 combat-style classifier (@shakti/sota-critical)#
v2-combat-style-classifier.ts implements per-player style classification, used
by the V2 AI director to matchup players with appropriate opponents.
- Constants:
V2_STYLE_CLASSIFICATION_EVENT_TOPIC = 'shakti.player.style.updated',V2_STYLE_CLASSIFICATION_SCHEMA_VERSION = 1. V2CombatStyle— the five classifiable play styles:boxer,kickboxer,striker,grappler,submission-specialist.V2CombatStyleTelemetryEvent— observed combat actions with range, strike kind, grappling kind, success, normalized damage, frame data, cancel usage, and pressure state.classifyV2CombatStyleconsumes aV2CombatStyleClassifierInput(player, match, ruleset, telemetry events) and returns aV2CombatStyleClassificationcarryingprimaryStyle,secondaryStyle,confidence,rangePreference(point-blank/close/mid/far),pressureTolerance,cancelConfidence, a per-stylescoreVector, a per-rulesetstyleAffinityVector, scoringevidence, andoffRollback: true.
5.5 Sister-monorepo consumption (planned, external)#
The integration boundary between Shakti and the V2 fighting-game project is a
documented contract only — no Shakti source file imports any @v2 package.
The V2 project documents how it consumes these libraries in
V2/docs/integration/shakti-ruleset-bridge.md and
V2/docs/integration/shakti-style-classification.md:
- V2 wraps the bridge in
@v2/shakti-ruleset-bridge, which serializes deterministic CSV rows forV2BalanceImporter. The wrapper preserves the ruleset-specific table differences across the MK / SF / Tekken / SC / DJ launch profiles — Tekken's extended actives, Street Fighter's drive-impact guard model, Soul Calibur's weapon reach and ring-out, and Def Jam'sdj-rushstamina each survive the transform intact instead of being averaged into one generic table. The bridge RPC isoff-rollbackand is rejected inside rollback frames;game-onlyreference cards are allowed (they need no real-sport antecedent). - V2 wraps the classifier in
@v2/shakti-style-classification, which turns the@shakti/sota-criticalstyle buckets (boxer,kickboxer,striker,grappler,submission-specialist) into AI Director matchup hints viabuildV2ShaktiAIDirectorMatchupPlan. Each hint carriespreferredOpponentStylesand thepairwiseMatchupstable the AI Director uses to pick opponents. Because the underlying classification isoffRollback: true, the wrapper downgrades any rollback-enabled session to anext-match-onlysnapshot so style data never influences a live deterministic frame.
Those @v2/* adapters live in the V2 monorepo, not in libs/shakti/. The
per-move reference-card corpus authoring for the full V2 launch roster is
planned work tracked outside this domain.
5.6 Frame-data output format#
The bridge's final output is a CSV row ready for downstream import. Each
ShaktiRulesetFrameDataRow carries all the information needed to drive a
fighting game's balance system:
- Startup / active / recovery frames
- On-hit and on-block advantage values
- Gap-to-followup, damage, hitstop
- Reach in Unreal units
- Juggle / combo / counter-hit scaling
- The profile's meter and stamina model references
- Special-rule flags
- The real-sport reference numerics the row was derived from
serializeShaktiFrameDataCsv(rows) serializes a batch of rows to a 26-column
CSV using the SHAKTI_FRAME_DATA_CSV_COLUMNS header.
6. Persistence Model#
Shakti defines its database schema as data rather than using a mainstream ORM. This fits the library-domain model: there is no running service to apply migrations, so the schema definition serves as a source of truth that can emit DDL when a deployment pipeline needs it.
@shakti/core/db-schema.ts uses a custom declarative TableDef model — not
Drizzle ORM, not Prisma. A hand-written SQL generator turns those definitions
into DDL.
SHAKTI_SCHEMA = 'shakti'— the target PostgreSQL schema name.- Type model:
ColumnType(14 values:uuid,text,varchar,integer,bigint,decimal,float,boolean,timestamp,date,json,jsonb,enum,array),ColumnDef,ForeignKeyRef,IndexDef,TableDef.
The 11 tables exported as ALL_SHAKTI_TABLES cover the data that must survive
across requests. In-memory knowledge-base content (asana taxonomies, exercise
libraries, API configuration records) does not need table rows — it lives in the
module-level Map stores:
| Table | Purpose |
|---|---|
practitioners |
Core practitioner profiles |
disciplines |
Physical disciplines |
discipline_styles |
Styles within a discipline |
techniques |
Techniques within a discipline/style |
exercises |
Exercise library |
programs |
Multi-week training programs |
sessions |
Logged training sessions |
personal_records |
Per-exercise PRs |
achievements |
Achievement definitions |
belt_ranks |
Martial-arts belt/rank systems |
streaks |
Consistency / training streaks |
Each TableDef carries columns (with nullability, defaults, foreign keys, enum
value lists, check constraints) and indexes (including gin trigram / JSONB
indexes). Utilities: getTableByName, getTableColumns, getRequiredColumns,
getForeignKeys, getTableIndexes, generateCreateTableSQL,
generateAllTablesSQL, countTotalColumns, countTotalIndexes.
There is no migration runner, ORM, or live database client in this domain — the schema module produces DDL strings only.
7. Event System#
@shakti/core/events.ts implements an in-process, synchronous event bus. It
is not Redis-backed and not a network broker. Its purpose is cross-module
decoupling within a single process — specifically, letting
@shakti/gamification react to training events without the session-logging code
knowing gamification exists.
7.1 Event envelope#
Every event in the system carries a standard metadata header for traceability.
Applications can correlate events back to their originating request using
correlationId, and understand causal chains using causationId:
ShaktiEventMetadata—eventId,correlationId, optionalcausationId,timestamp,version,source, optionaluserId/practitionerId.ShaktiEvent<T>—{ type, metadata, payload }.generateEventId()produces monotonically-suffixedevt_<ts>_<n>ids;createEventMetadata(...)builds metadata.
7.2 Event types#
ShaktiEventMap keys the 20 supported event types (also exported as
ALL_EVENT_TYPES). Each event type has a strongly-typed payload interface,
preventing consumers from having to cast or check payload shape at runtime:
| Event type | Payload interface |
|---|---|
session.started |
SessionStartedPayload |
session.completed |
SessionCompletedPayload |
session.paused |
SessionPausedPayload |
session.resumed |
SessionResumedPayload |
exercise.performed |
ExercisePerformedPayload |
technique.attempted |
TechniqueAttemptedPayload |
personal_record.achieved |
PersonalRecordPayload |
program.enrolled |
ProgramEnrolledPayload |
program.completed |
ProgramCompletedPayload |
workout.generated |
WorkoutGeneratedPayload |
form_analysis.completed |
FormAnalysisPayload |
achievement.unlocked |
AchievementUnlockedPayload |
streak.milestone |
StreakMilestonePayload |
challenge.joined |
ChallengeJoinedPayload |
challenge.completed |
ChallengeCompletedPayload |
certification.earned |
CertificationEarnedPayload |
belt.promotion |
BeltPromotionPayload |
injury.reported |
InjuryReportedPayload |
recovery.updated |
RecoveryStatusPayload |
biometric.synced |
BiometricSyncedPayload |
FormAnalysisPayload carries a corrections array of FormCorrection
({ cue, severity, description }, severity ∈ info/warning/critical).
The separate @shakti/sota-critical V2 classifier publishes off-rollback under
the topic string shakti.player.style.updated (defined as its own constant,
independent of ShaktiEventMap).
7.3 Bus operations#
The bus API covers the full lifecycle of event-driven communication, including batching for performance, dead-letter handling for fault tolerance, and replay for debugging and testing:
subscribe(type, handler)→ returns an unsubscribe function.publish(type, payload, meta?)→ builds an event, appends it to the in-memoryeventLog, dispatches synchronously to all handlers, and routes handler exceptions to a dead-letter queue.publishBatched(...)/flushBatch()— batches events, flushing on a 100 ms timer or at 50 events (BATCH_INTERVAL_MS = 100,MAX_BATCH_SIZE = 50).- Dead-letter handling:
getDeadLetterQueue(),retryDeadLetterEvents()(MAX_RETRY = 3). - Replay / inspection:
replayEvents(from, to?),getEventLog(). - Serialization / versioning:
serializeEvent,deserializeEvent,migrateEventVersion. - Monitoring:
getEventMetrics()→EventMetrics(published,handled,failed,batched,deadLetterSize,logSize,subscriberCount). resetEventSystem()clears all bus state for test isolation.
8. Technology Stack and Build#
The following table summarizes the technology decisions for the Shakti domain.
The most notable choices are the deliberate absence of runtime dependencies
(every library ships with an empty dependencies map) and the custom validation
and persistence layers that avoid third-party frameworks.
| Layer | Technology |
|---|---|
| Language | TypeScript, ESM ("type": "module") |
| Runtime dependencies | None — every libs/shakti/* package.json has an empty dependencies map |
| Validation | Hand-written validate* functions returning string[] (no Zod/Yup/Joi) |
| Persistence model | Custom declarative TableDef + SQL string generator targeting PostgreSQL schema shakti (no ORM) |
| Events | In-process synchronous bus in @shakti/core |
| Hashing | Node node:crypto (createHash) — used by the fighting-ruleset bridge and V2 classifier |
| Build executor | @nx/js:tsc (most libraries); nx:run-commands for @shakti/fighting-ruleset-bridge |
| Test executor | @nx/vite:test / Vitest; nx:run-commands running Vitest for fighting-ruleset-bridge |
| Nx tags | scope:shakti, layer:domain, type:lib (the bridge adds domain:combat) |
Each library co-locates *.spec.ts Vitest suites next to its source. Direct
invocation when Nx is unavailable:
cd libs/shakti/<library> && npx tsc --noEmit and npx vitest run.
Note: the
libs/shakti/README.mdquick-start examples (e.g.createShaktiClient,shakti.workouts.generate) describe an aspirational client surface and an API port. They are illustrative; the implementedsdkandapilibraries are configuration/utility modules, and no Shakti library binds an HTTP port.
9. Acceptance Criteria#
A change to the Shakti domain is acceptable when all of the following conditions hold. These criteria exist to prevent the domain from drifting toward stubs — each criterion is designed to be independently verifiable.
- No fabricated surface. Every type, enum value, function, table, and event
documented or added is present in
libs/shakti/*source. - Knowledge-base coherence. New registry records are typed against the
module's declared interfaces and reachable through that module's
getAll*/get*/search*/count*accessors. - Domain correctness. Calculation helpers compute real domain formulas (e.g. Brzycki 1RM, heart-rate reserve, frame conversion) and tests assert specific computed values, not just shape or truthiness.
- Validation parity. Each schema interface that needs validation has a
matching
validate*function returning astring[]of messages. - Bridge determinism.
transformBiomechanicsToFrameDataproduces identical output for identical input; non-game-only moves are rejected without a realsourceSportandshaktiTechnique. - Self-containment. Libraries add no runtime npm dependencies and no cross-domain imports; the standalone-library model is preserved.
- Build and lint.
npx tsc --noEmitand the library's Vitest suite pass.