/* * Tardygrada — Executor Implementation * * Walks the instruction list, spawns agents on the VM. * Then starts the MCP server so the world can connect. */ #include "exec.h" #include "vm/util.h" #include "terraform.h" #include "../verify/pipeline.h" #include "../coordinate/bridge.h" #include #include #include #include #include #include static void exec_print(const char *s) { tardy_write(STDERR_FILENO, s, strlen(s)); } int tardy_exec(tardy_vm_t *vm, const tardy_program_t *prog) { if (!vm || !prog) return -1; tardy_uuid_t current_agent = vm->root_id; for (int i = 0; i < prog->count; i++) { const tardy_instruction_t *inst = &prog->instructions[i]; switch (inst->opcode) { case OP_SPAWN_AGENT: { /* Create a named agent in root context */ int64_t zero = 0; tardy_uuid_t id = tardy_vm_spawn(vm, vm->root_id, inst->name, TARDY_TYPE_AGENT, inst->trust, &zero, sizeof(int64_t)); tardy_agent_t *agent = tardy_vm_find(vm, id); if (agent) current_agent = id; exec_print("[tardygrada] agent "); exec_print(inst->name); exec_print(" spawned\n"); break; } case OP_SPAWN_VALUE: { /* Create a value agent in current agent's context */ switch (inst->type) { case TARDY_TYPE_INT: { int64_t val = inst->int_val; tardy_vm_spawn(vm, current_agent, inst->name, TARDY_TYPE_INT, inst->trust, &val, sizeof(int64_t)); break; } case TARDY_TYPE_FLOAT: { double val = inst->float_val; tardy_vm_spawn(vm, current_agent, inst->name, TARDY_TYPE_FLOAT, inst->trust, &val, sizeof(double)); break; } case TARDY_TYPE_STR: { tardy_vm_spawn(vm, current_agent, inst->name, TARDY_TYPE_STR, inst->trust, inst->str_val, strlen(inst->str_val) + 1); break; } case TARDY_TYPE_BOOL: { int64_t val = inst->bool_val ? 1 : 0; tardy_vm_spawn(vm, current_agent, inst->name, TARDY_TYPE_BOOL, inst->trust, &val, sizeof(int64_t)); break; } default: break; } exec_print("[tardygrada] "); if (inst->trust >= TARDY_TRUST_DEFAULT) exec_print("let "); exec_print(inst->name); exec_print(" = ..."); if (inst->trust == TARDY_TRUST_VERIFIED) exec_print(" @verified"); else if (inst->trust == TARDY_TRUST_HARDENED) exec_print(" @hardened"); else if (inst->trust == TARDY_TRUST_SOVEREIGN) exec_print(" @sovereign"); exec_print("\n"); break; } case OP_RECEIVE: { exec_print("[tardygrada] receive(\""); exec_print(inst->str_val); exec_print("\")"); if (inst->grounded) { exec_print(" grounded_in("); exec_print(inst->ontology); exec_print(")"); } exec_print(" -> pending\n"); /* Spawn empty mutable agent (will be filled via MCP submit_claim) */ const char *empty = ""; tardy_vm_spawn(vm, current_agent, inst->name, TARDY_TYPE_STR, TARDY_TRUST_MUTABLE, empty, 1); break; } case OP_EXEC: { exec_print("[tardygrada] exec(\""); exec_print(inst->str_val); exec_print("\")\n"); /* Fork and exec the command, capture stdout */ int pipefd[2]; if (pipe(pipefd) < 0) { exec_print("[tardygrada] pipe failed\n"); const char *err = "exec: pipe failed"; tardy_vm_spawn(vm, current_agent, inst->name, TARDY_TYPE_STR, TARDY_TRUST_MUTABLE, err, strlen(err) + 1); break; } pid_t pid = fork(); if (pid < 0) { close(pipefd[0]); close(pipefd[1]); const char *err = "exec: fork failed"; tardy_vm_spawn(vm, current_agent, inst->name, TARDY_TYPE_STR, TARDY_TRUST_MUTABLE, err, strlen(err) + 1); break; } if (pid == 0) { /* Child: redirect stdout to pipe, exec shell */ close(pipefd[0]); dup2(pipefd[1], STDOUT_FILENO); close(pipefd[1]); /* Redirect stderr to /dev/null */ int devnull = open("/dev/null", O_WRONLY); if (devnull >= 0) { dup2(devnull, STDERR_FILENO); close(devnull); } execl("/bin/sh", "sh", "-c", inst->str_val, (char *)NULL); _exit(127); } /* Parent: read output from pipe */ close(pipefd[1]); char output[4096]; int total = 0; ssize_t n; while ((n = read(pipefd[0], output + total, sizeof(output) - (size_t)total - 1)) > 0) total += (int)n; output[total] = '\0'; close(pipefd[0]); int wstatus; waitpid(pid, &wstatus, 0); int exit_code = WIFEXITED(wstatus) ? WEXITSTATUS(wstatus) : -1; /* Trim trailing newline */ while (total > 0 && (output[total - 1] == '\n' || output[total - 1] == '\r')) output[--total] = '\0'; /* Log output preview */ exec_print("[tardygrada] -> \""); { size_t preview_len = (total > 0 && total < 80) ? (size_t)total : 80; if (preview_len > (size_t)total && total > 0) preview_len = (size_t)total; char preview[81]; memcpy(preview, output, preview_len); preview[preview_len] = '\0'; exec_print(preview); if (total > 80) exec_print("..."); } exec_print("\" (exit "); { char ec[8]; ec[0] = '0' + (char)(exit_code % 10); ec[1] = '\0'; exec_print(ec); } exec_print(")\n"); if (exit_code != 0 || total == 0) { /* Command failed — spawn as mutable with error info */ char err_msg[256]; int elen = snprintf(err_msg, sizeof(err_msg), "exec failed (exit %d): %.200s", exit_code, output); tardy_vm_spawn(vm, current_agent, inst->name, TARDY_TYPE_STR, TARDY_TRUST_MUTABLE, err_msg, (size_t)elen + 1); } else { /* Command succeeded — spawn with output */ tardy_trust_t trust = inst->grounded ? (inst->trust >= TARDY_TRUST_DEFAULT ? inst->trust : TARDY_TRUST_MUTABLE) : TARDY_TRUST_MUTABLE; tardy_vm_spawn(vm, current_agent, inst->name, TARDY_TYPE_STR, trust, output, (size_t)total + 1); } /* Record in conversation */ tardy_agent_t *spawned = tardy_vm_find_by_name( vm, current_agent, inst->name); if (spawned) { char conv[512]; snprintf(conv, sizeof(conv), "exec: %.400s", inst->str_val); tardy_vm_converse(vm, spawned->id, "system", conv); } break; } case OP_FORK: tardy_fork(vm, current_agent, inst->str_val, inst->name[0] ? inst->name : NULL); break; case OP_FREEZE: { exec_print("[tardygrada] freeze "); exec_print(inst->name); if (inst->trust == TARDY_TRUST_VERIFIED) exec_print(" @verified"); else if (inst->trust == TARDY_TRUST_HARDENED) exec_print(" @hardened"); else if (inst->trust == TARDY_TRUST_SOVEREIGN) exec_print(" @sovereign"); exec_print("\n"); tardy_agent_t *target = tardy_vm_find_by_name(vm, current_agent, inst->name); if (target) { tardy_uuid_t frozen = tardy_vm_freeze(vm, target->id, inst->trust); if (frozen.hi == 0 && frozen.lo == 0) { exec_print("[tardygrada] freeze failed (already immutable?)\n"); } } else { exec_print("[tardygrada] agent not found: "); exec_print(inst->name); exec_print("\n"); } break; } case OP_SET_SEMANTICS: { exec_print("[tardygrada] @semantics("); exec_print(inst->sem_key); exec_print(": "); exec_print(inst->sem_value); exec_print(")\n"); /* Apply semantics override to current agent */ const tardy_semantics_t *current_sem = tardy_vm_get_semantics(vm, current_agent); tardy_semantics_t updated = *current_sem; /* Parse key and set value */ if (strcmp(inst->sem_key, "truth.min_confidence") == 0) { float f = 0.0f; const char *s = inst->sem_value; int i = 0; for (; s[i] && s[i] != '.'; i++) f = f * 10.0f + (s[i] - '0'); if (s[i] == '.') { i++; float frac = 0.1f; for (; s[i]; i++) { f += (s[i] - '0') * frac; frac *= 0.1f; } } updated.truth.min_confidence = f; } else if (strcmp(inst->sem_key, "truth.min_consensus_agents") == 0) { updated.truth.min_consensus_agents = (int)inst->int_val; if (updated.truth.min_consensus_agents == 0) { /* Parse from string */ int v = 0; const char *s = inst->sem_value; for (int i = 0; s[i]; i++) v = v * 10 + (s[i] - '0'); updated.truth.min_consensus_agents = v; } } else if (strcmp(inst->sem_key, "pipeline.min_passing_layers") == 0) { int v = 0; const char *s = inst->sem_value; for (int i = 0; s[i]; i++) v = v * 10 + (s[i] - '0'); updated.pipeline.min_passing_layers = v; } tardy_vm_set_semantics(vm, current_agent, &updated); break; } case OP_COORDINATE: { exec_print("[tardygrada] coordinate {"); exec_print(inst->coord_agents); exec_print("} on(\""); exec_print(inst->coord_task); exec_print("\")\n"); /* Parse comma-separated agent names */ char names[256]; strncpy(names, inst->coord_agents, sizeof(names) - 1); names[sizeof(names) - 1] = '\0'; tardy_uuid_t agent_ids[16]; int agent_count = 0; char *tok = names; char *next; while (tok && agent_count < 16) { next = strchr(tok, ','); if (next) *next = '\0'; /* Trim whitespace */ while (*tok == ' ') tok++; char *end = tok + strlen(tok) - 1; while (end > tok && *end == ' ') *end-- = '\0'; if (*tok) { tardy_agent_t *a = tardy_vm_find_by_name(vm, current_agent, tok); if (a) { agent_ids[agent_count++] = a->id; } else { exec_print("[tardygrada] agent not found: "); exec_print(tok); exec_print("\n"); } } tok = next ? next + 1 : NULL; } if (agent_count < 2) { exec_print("[tardygrada] need at least 2 agents for coordination\n"); break; } /* Try brain-in-the-fish coordination engine first */ tardy_bitf_conn_t bitf; int bitf_ok = tardy_bitf_connect(&bitf, TARDY_BITF_SOCKET_PATH); if (bitf_ok == 0) { exec_print("[tardygrada] brain-in-the-fish connected\n"); /* Collect agent name strings */ char names2[256]; strncpy(names2, inst->coord_agents, sizeof(names2) - 1); names2[sizeof(names2) - 1] = '\0'; const char *agent_strs[16]; int asc = 0; char *t2 = names2; char *n2; while (t2 && asc < 16) { n2 = strchr(t2, ','); if (n2) *n2 = '\0'; while (*t2 == ' ') t2++; if (*t2) agent_strs[asc++] = t2; t2 = n2 ? n2 + 1 : NULL; } tardy_bitf_result_t result; tardy_bitf_coordinate(&bitf, inst->coord_task, agent_strs, asc, &result); tardy_bitf_disconnect(&bitf); if (result.success) { char msg[128]; snprintf(msg, sizeof(msg), "[tardygrada] consensus: confidence=%.0f%% rounds=%d\n", result.confidence * 100, result.rounds); exec_print(msg); } else { exec_print("[tardygrada] coordination failed: "); exec_print(result.error); exec_print("\n"); } } else { /* Fallback: send task to agent inboxes */ for (int ci = 0; ci < agent_count; ci++) { tardy_vm_send(vm, current_agent, agent_ids[ci], inst->coord_task, strlen(inst->coord_task) + 1, TARDY_TYPE_STR); } exec_print("[tardygrada] dispatched to "); char cntstr[8]; cntstr[0] = '0' + (char)agent_count; cntstr[1] = '\0'; exec_print(cntstr); exec_print(" agents (bitf offline)\n"); } break; } case OP_ADD_INVARIANT: { exec_print("[tardygrada] invariant("); /* Print invariant type */ switch (inst->invariant_type) { case 0: exec_print("type_check"); break; case 1: exec_print("range"); break; case 2: exec_print("non_empty"); break; case 3: exec_print("trust_min"); break; default: exec_print("unknown"); break; } exec_print(")\n"); /* Add invariant to current agent's constitution */ tardy_agent_t *agent = tardy_vm_find(vm, current_agent); if (agent) { tardy_invariant_t inv = {0}; inv.type = (tardy_invariant_type_t)inst->invariant_type; inv.min_val = inst->inv_min; inv.max_val = inst->inv_max; inv.trust_arg = inst->inv_trust; tardy_constitution_add(&agent->constitution, inv); } break; } case OP_HALT: exec_print("[tardygrada] program loaded\n"); return 0; } } return 0; } int tardy_exec_file(const char *path) { /* Compile */ tardy_program_t prog; if (tardy_compile_file(&prog, path) != 0) { exec_print("[tardygrada] compile error: "); exec_print(prog.error); exec_print("\n"); return 1; } /* Create VM */ tardy_vm_t *vm = (tardy_vm_t *)mmap(NULL, sizeof(tardy_vm_t), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (vm == MAP_FAILED) return 1; tardy_vm_init(vm, NULL); /* Execute program */ tardy_exec(vm, &prog); /* Start MCP server */ exec_print("[tardygrada] MCP server starting on stdio\n"); tardy_mcp_server_t srv; tardy_mcp_init(&srv, vm); tardy_mcp_run(&srv); /* Cleanup */ tardy_vm_shutdown(vm); munmap(vm, sizeof(tardy_vm_t)); return 0; }