upcode_operation_errors{operation="transform",error_type="fatal",code=
# TYPE upcode_operation_duration histogram
upcode_operation_duration_bucket{operation="transform",le="0.005"} 120
upcode_operation_duration_bucket{operation="transform",le="0.01"} 1800
upcode_operation_duration_bucket{operation="transform",le="+Inf"} 1847
upcode_operation_duration_sum{operation="transform"} 4.523
upcode_operation_duration_count{operation="transform"} 1847
Custom Metrics Registration API
POST /v2/metrics/register Content-Type: application/json Authorizatio
{
"name": "upcode_plugin_transforms_total",
"type": "counter",
"description": "Total plugin transforms applied",
"labels": ["pluginId", "fixType"],
"resetOnRead": false
}
Response:
{
"name": "upcode_plugin_transforms_total",
"registered": true
}
Overlapping registration (same name + type) returns 409 Conflict.
Metric Labels and Dimensions
All built-in metrics carry these standard dimensions:
Label Values Description
operation Operation name
Label Values Description
scan , transform , analyze ,
list_rules
vscode , wordpress ,
Deployment
topology shopify , strapi , cli ,
topology
docker
transient , fatal ,
error_type Error taxonomy
user_caused , internal
javascript , typescript , Source
language
css , php , python language
Specific rule
rule_id free-form string
identifier
Custom metrics may attach arbitrary label keys.
SLO Dashboard Queries
PromQL snippets for SLO tracking:
# Transform error rate (target < 1%)
sum(rate(upcode_operation_errors{operation="transform"}[5m]))
/ sum(rate(upcode_operation_rate{operation="transform"}[5m]))
# P99 transform latency (target < 2s)
histogram_quantile(0.99,
sum(rate(upcode_operation_duration_bucket{operation="transform"}[5m]
# Parser availability (target 100%)
sum(rate(upcode_parser_initializations_total{status="success"}[5m]))
/ sum(rate(upcode_parser_initializations_total[5m]))
# Batch job success rate
sum(rate(upcode_jobs_completed_total{state="succeeded"}[10m]))
/ sum(rate(upcode_jobs_completed_total[10m]))
Admin and Management API
All admin endpoints require Authorization: Bearer
$UPCODE_ADMIN_API_KEY in addition to the standard API key header.
Plugin Management Endpoints
GET /v2/admin/plugins HTTP/1.1 Authorization: Bearer $UPCODE_ADMIN_AP
{
"plugins": [
{
"id": "plugin-auth-enforcer",
"version": "2.1.0",
"enabled": true,
"loadedAt": "2026-01-15T14:00:00.000Z",
"hooks": ["transformAST", "onLoad"]
},
{
"id": "plugin-legacy-shim",
"version": "1.4.0",
"enabled": false,
"loadedAt": null,
"hooks": []
}
]
}
POST /v2/admin/plugins/:id/enable HTTP/1.1
204 No Content
POST /v2/admin/plugins/:id/disable HTTP/1.1
204 No Content
POST /v2/admin/plugins/:id/uninstall HTTP/1.1
Deletes plugin package and clears [Link] entry. Returns
Rule Management Endpoints
GET /v2/admin/rules HTTP/1.1
{
"ruleSets": [
{ "id": "latest", "version": "10.0.0", "rulesCount": 124, "active"
{ "id": "strict", "version": "8.0.0", "rulesCount": 87, "active":
]
}
POST /v2/admin/rules/:id/reload HTTP/1.1
Reloads rule set from package. Returns updated RuleSetStatus .
Pending transforms are completed with old rules; new transforms use
the reloaded set.
{
"id": "latest",
"version": "10.0.0",
"reloadedAt": "2026-01-15T14:50:00.000Z"
}
Cache Management
GET /v2/admin/cache/stats HTTP/1.1
{
"hits": 184230,
"misses": 4321,
"hitRate": 0.977,
"entries": 8912,
"sizeBytes": 52428800,
"evictions": 210,
"oldestEntryAgeMs": 180000
}
POST /v2/admin/cache/invalidate HTTP/1.1 Content-Type: application/js
{
"scope": "all",
"reason": "rule version changed to 10.1.0"
}
{ "invalidated": 8912 }
POST /v2/admin/cache/warmup HTTP/1.1
{
"paths": ["./src/**/*.ts", "./src/**/*.js"]
}
Returns 202 Accepted with job ID for progress polling.
Backup Management
GET /v2/admin/backups HTTP/1.1
{
"workspaceId": "ws-abc123",
"snapshots": [
{ "id": "snap-001", "timestamp": "2026-01-15T12:00:00.000Z", "file
{ "id": "snap-002", "timestamp": "2026-01-14T12:00:00.000Z", "file
]
}
POST /v2/admin/backups/restore HTTP/1.1
{
"snapshotId": "snap-001",
"dryRun": false,
"backupCurrent": true
}
{ "jobId": "job-restore-xyz", "statusUrl": "/jobs/job-restore-xyz" }
POST /v2/admin/backups/prune HTTP/1.1
{
"retainCount": 7,
"olderThanDays": 14
}
System Info Endpoint
GET /v2/admin/system/info HTTP/1.1
{
"version": "10.0.0",
"buildCommit": "abc123def456",
"buildTimestamp": "2026-01-10T08:00:00.000Z",
"topology": "vscode",
"hostPlatform": "darwin",
"hostArch": "arm64",
"nodeVersion": "v22.11.0",
"parserVersion": "10.0.0",
"rulesCount": 124,
"pluginsEnabled": 3,
"diskFreeGb": 142,
"memoryUsedMb": 87,
"uptimeSec": 1423,
"correlationId": "req-admin-001"
}
Appendix: Complete gRPC Service
Definitions
Full .proto File Content with All Messages, Enums,
Services
syntax = "proto3";
package upcode.v1;
import "google/protobuf/[Link]";
import "google/protobuf/[Link]";
import "google/protobuf/[Link]";
// Top-level services
service UpcodeCore { rpc Analyze(AnalyzeRequest) returns (AnalyzeRespo
service WorkspaceScan {
rpc Scan(WorkspaceRequest) returns (stream ScanEvent);
}
service LiveTransform {
rpc Run(stream TransformInstruction) returns (stream LiveTransformEv
}
service RuleManagement {
rpc List(ListRulesRequest) returns (ListRulesResponse);
rpc Reload(ReloadRulesetRequest) returns (RulesetReloadResponse);
rpc ValidateRule(ValidateRuleRequest) returns (ValidateRuleResponse)
}
service BackupService {
rpc CreateSnapshot(CreateSnapshotRequest) returns (SnapshotResponse)
rpc ListSnapshots(ListSnapshotsRequest) returns (ListSnapshotsRespon
rpc Restore(RestoreSnapshotRequest) returns (stream RestoreProgress)
}
// Shared messages
message AnalyzeRequest {
oneof input {
string source = 1;
string file_path = 2;
}
string language_hint = 3;
ScanOptions options = 4;
string ruleset_id = 5;
}
message AnalyzeResponse {
repeated RuleMatch matches = 1;
[Link] total_duration = 2;
optional UpcodeGrpcError error = 3;
}
message WorkspaceRequest {
string workspace_id = 1;
repeated string include_paths = 2;
repeated string exclude_glob = 3;
string ruleset_id = 4;
ScanOptions options = 5;
}
message ScanEvent {
oneof event {
ScanFileResult file_result = 1;
double progress_percent = 2;
UpcodeGrpcError file_error = 3;
}
[Link] timestamp = 4;
}
message ScanFileResult {
string file_path = 1;
repeated RuleMatch matches = 2;
[Link] parse_duration = 3;
}
message TransformInstruction {
string fix_id = 1;
string file_path = 2;
bool confirm = 3;
string idempotency_key = 4;
}
message LiveTransformEvent {
oneof event {
LiveTransformProgress progress = 1;
LiveTransformResult result = 2;
LiveTransformError error = 3;
}
}
message LiveTransformProgress {
string file_path = 1;
double percent = 2;
string stage = 3;
}
message LiveTransformResult {
string file_path = 1;
ApplyChange change = 2;
}
message ApplyChange {
string fix_id = 1;
string backup_path = 2;
int32 lines_changed = 3;
}
message LiveTransformError {
string file_path = 1;
UpcodeGrpcError error = 2;
}
message ScanOptions {
uint32 max_matches_per_file = 1;
bool include_branch = 2;
bool fail_on_warn = 3;
}
message UpcodeGrpcError {
string code = 1;
string message = 2;
map<string, string> context = 3;
}
// RuleManagement
message ListRulesRequest { string ruleset_id = 1; }
message ListRulesResponse { repeated RuleDefinition rules = 1; }
message RuleDefinition {
string id = 1;
string version = 2;
string display_name = 3;
string description = 4;
Severity severity = 5;
bool enabled = 6;
}
message ReloadRulesetRequest { string ruleset_id = 1; }
message RulesetReloadResponse {
string ruleset_id = 1;
[Link] reloaded_at = 2;