Submitted to the All Things Agentic 2026 hackathon. Milestone: H1-A Agent Core.
Disclosure
InsightValues is a preexisting platform (Flutter + Supabase) developed before this hackathon. The IVE agent — the strategic execution layer described in this article — is new, created during the hackathon period. The agent integrates with InsightValues data structures via controlled tool access.
Final Hackathon Build Update — August 2026
The sections below (1–20) describe the H1-A milestone exactly as it was built and are preserved unchanged as historical development record. This section describes what has been built since, up to the final submission.
Since H1-A, the agent went through three further milestones — H1-B (Cloud Run deployment), H1-C (authenticated Supabase tool gateway, JWT/JWKS validation), and H1-C2 (read-after-write verification, production end-to-end acceptance) — followed by a final commit adding persistent decision memory. Here is what changed, stated precisely:
| Capability | H1-A (original article) | Current (final build) |
|---|---|---|
| Deployment | Not deployed | Deployed on Google Cloud Run (europe-west2) |
| Data | In-memory demo dict | Real Supabase tables (projects, action_queue, business_memory) under Row Level Security |
| Auth | None | Supabase JWT validated via JWKS (ES256); user identity derived from the token, never from the request body |
| Tools | get_demo_project_context, create_demo_action |
get_project_context, create_action, get_action, write_agent_memory |
| Verification | In-memory store lookup | Read-after-write: get_action re-reads the row from the database before the agent reports success |
| Memory | None | Verified strategic decisions can be persisted to durable business_memory and retrieved as context (recent_memories) in future executions |
This was verified with a real call to the deployed Cloud Run service — a live Supabase JWT, a real InsightValues project, HTTP 200, verification_status: verified — documented in the repository’s H1-C2 production acceptance record, including a database row confirmed in action_queue traceable back to that execution via its execution_id.
Corrected idempotency claim: action creation uses a deterministic ID derived from (project_id, execution_id, action_key), so a repeated call with the same three values does not create a duplicate row — the database’s own primary-key constraint rejects the second insert. This is real, code-level protection against duplicate actions. It is not the same as a blanket “exactly-once” guarantee across every possible retry/network scenario, which has not been separately demonstrated.
What is still not true, stated as plainly as the rest of this article: there is no automatic retry logic, no persistent ADK session across separate calls (each request is independent), and the agent does not learn or improve over time. The memory-write step (write_agent_memory) is correct by code review and its companion read path is used in production, but the write itself has not yet been exercised by a dedicated production smoke test.
Maturity label for this build, precisely: a production-deployed prototype — the infrastructure, auth, and persistence are real and live-tested, not a hackathon-only demo; it is not, however, a mature, rate-limited, multi-tenant production product.
1. The Problem
Most AI tools today are good at answering questions. They summarize, analyze, explain. What they rarely do is help you move from understanding to action.
IVE (InsightValues Strategic Execution Agent) is an attempt to close that gap. Given a strategic project context — opportunities, current actions, resource constraints — IVE reasons over the situation, identifies the highest-leverage action to take next, and registers it with a verifiable, idempotent record.
The scope is deliberately narrow for H1-A: one project, one action per execution, demo data. The architecture is designed to extend.
2. Why an Agent, Not a Prompt
A simple prompt to a language model can produce a suggested action. But it cannot:
- Retrieve structured project context on demand
- Register the action in a verifiable store
- Be tested for idempotency (same input → same output, no duplicate actions)
- Emit structured observability events for each step
- Be constrained to a defined number of reasoning iterations
An agent architecture makes all of these possible. The agent loop — where the model decides whether to call tools or produce a final answer — is what connects reasoning to execution.
3. Technology Stack
| Component | Choice | Reason |
|---|---|---|
| Agent framework | Google ADK 2.7+ | Native Gemini integration, LlmAgent with tool support |
| Model | Gemini 3.5 Flash | Speed + instruction-following at low temperature |
| Python | 3.11+ | Type hints, dataclasses, match expressions |
| Testing | pytest 8.0+ | 10 required test cases (T01-T10) |
| Session service | InMemorySessionService (H1-A) | No persistence needed for demo milestone |
| Storage | In-memory dict (H1-A) | Supabase planned for H1-C |
4. Google ADK: What It Is and What It Provides
Google ADK (Agent Development Kit) is Google’s framework for building agents that run on Gemini models. In this project, we use version 2.7+.
The core primitive is LlmAgent — a class that wraps a Gemini model and a list of Python functions (tools). When the agent runs, ADK handles the loop: send the instruction + context to Gemini, receive either a tool call or a final answer, execute the tool if called, feed the result back, repeat until Gemini produces a final answer or the iteration cap is reached.
from google.adk.agents import LlmAgent
root_agent = LlmAgent(
name="ive_strategic_execution_agent",
model="gemini-3.5-flash",
instruction=_INSTRUCTION,
tools=[get_demo_project_context, create_demo_action],
temperature=0.2,
max_output_tokens=2048,
)
The instruction string is the agent’s behavioral contract. It defines what the agent does, in what order, and what it must not do.
5. The Model: Gemini 3.5 Flash
IVE uses gemini-3.5-flash. This is confirmed in both ive_agent/agent.py and in the test suite (T07: assert root_agent.model == "gemini-3.5-flash").
The choice reflects the requirements of this task: structured tool-calling behavior, deterministic output at low temperature, and fast iteration during development. Temperature is set to 0.2 to minimize randomness in action selection.
6. Architecture: The 5-Step Agent Loop
The agent instruction defines a structured workflow in five steps:
STEP 1 — LOAD CONTEXT
Call get_demo_project_context() to retrieve the current project state.
STEP 2 — IDENTIFY THE GAP
Analyze the opportunities and current actions. Identify the highest-leverage
gap: what is the most impactful action not yet underway?
STEP 3 — CREATE THE ACTION
Call create_demo_action() with a single, well-justified action.
Create exactly ONE action.
STEP 4 — VERIFY
Confirm the action was created successfully by checking the returned status.
STEP 5 — EXPLAIN
Provide a clear explanation of: what action was created, why it was selected,
what outcome it is expected to drive, and confirmation that it was registered.
The README describes this as: GOAL → CONTEXT → REASON → PLAN → ACTION → VERIFY → EXPLAIN
The loop guard (RunConfig(max_llm_calls=10) in the acceptance run) ensures the agent cannot run indefinitely. In practice, a well-formed run requires approximately 4 LLM calls: one for reasoning, one tool call to get context, one tool call to create the action, and one for the final explanation.
7. Tool 1: get_demo_project_context()
This tool returns a fully deterministic project context dict — no network calls, no external dependencies. It is designed to simulate what a real integration with InsightValues project data would return.
The returned structure includes:
project_id,name,description,status— project identitypriority_score,opportunity_score— numeric signals (0-100)current_actions— list of actions already in progressopportunities— list of strategic opportunities withfinal_scorestrategic_gap— a text description of the key gap to closeknowledge_items_count,revenue_potential— context signals
The demo data uses project_id: "demo-project-001". This is hardcoded and intentional for H1-A.
Test T01 validates the schema of the returned dict.
8. Tool 2: create_demo_action()
This tool registers a strategic action. It accepts 9 parameters:
| Parameter | Type | Constraint |
|---|---|---|
| execution_id | str | Required, non-empty |
| action_key | str | Required, forms idempotency key with execution_id |
| title | str | Required, non-empty |
| action_type | str | Must be one of: tarefa, conteúdo, campanha, produto, análise |
| priority | int | 1-5 |
| impact_score | int | 0-100 (clamped) |
| effort_score | int | 0-100 (clamped) |
| roi_score | int | 0-100 (clamped) |
| rationale | str | Required |
The tool returns a dict that includes:
action_id— a uuid4 identifierstatus—"created"or"already_exists"idempotent_replay— boolean flagorigin— always"ive_agent"
9. Reasoning to Action: How the Agent Decides
The agent receives the project context from Tool 1 and reasons over it before calling Tool 2. At temperature 0.2, Gemini consistently:
- Identifies the opportunity with the highest
final_scorethat isn’t represented incurrent_actions - Maps it to an appropriate
action_type - Assigns priority and scores based on the context signals
- Writes a rationale grounded in the
strategic_gaptext
The instruction enforces “Create exactly ONE action” — this prevents the agent from attempting to solve the entire strategic context in one execution.
10. Idempotency: Why It Matters
An agent that creates duplicate actions is worse than no agent at all. IVE enforces idempotency at the tool level.
The idempotency key is a composite: (execution_id, action_key). If create_demo_action() is called twice with the same execution_id and action_key, the second call returns the existing record with status: "already_exists" and idempotent_replay: true — without creating a new entry.
idempotency_key = (execution_id, action_key)
if idempotency_key in _action_store:
return _action_store[idempotency_key] # return existing, no mutation
Tests T03 validate this behavior: same key → same action_id; different key → new action.
11. Verification
After the action is created, the agent explicitly verifies success before producing its final explanation (Step 4 of the instruction). The acceptance run (acceptance_run.py) also performs programmatic verification: it checks that the action_id returned by the tool is present in _action_store.
This double-verification (model-level + programmatic) means the acceptance run provides a strong signal that the full loop executed correctly.
12. Agent Memory: In-Memory at H1-A
At the H1-A milestone, all action storage is in-memory:
_action_store: dict[tuple[str, str], dict[str, Any]] = {}
This dict is reset each time the process starts. There is no persistence between runs.
Supabase integration is planned for H1-C. The architecture is designed for this: create_demo_action() and lookup_action() are isolated functions with no external I/O, making the swap to a persistent backend straightforward.
13. Observability: Structured Events
IVE emits structured JSON events to stdout at each step of the execution. There are 9 required event types:
AGENT_STARTED
CONTEXT_REQUESTED
CONTEXT_LOADED
PLAN_CREATED
TOOL_STARTED
TOOL_SUCCEEDED
RESULT_VERIFIED
AGENT_COMPLETED
AGENT_FAILED
Each event includes: timestamp, event_type, execution_id, summary. Optional fields: tool_name, duration_ms.
Events are emitted via print(evt.to_json(), flush=True) — one JSON object per line. The code comment in events.py notes that Cloud Run’s logging infrastructure picks these up automatically via stdout, which is the intended deployment target (though no Cloud Run deployment config exists in H1-A).
Test T05 validates event schema, JSON validity, and log collection. Test T06 validates that events contain no secret patterns (api_key, password, secret, token, credential, private_key).
14. Safety and Ownership Boundaries
The agent is constrained in several ways:
- Scope: one project, one action per run
- Loop guard:
RunConfig(max_llm_calls=10)in acceptance run (ADK default is 500) - Validation:
action_typemust be from a defined set;titlemust be non-empty;prioritymust be 1-5 - No secrets in events:
has_no_secrets()enforced at the event level (T06) - Idempotency: prevents runaway action creation across retries
- Deterministic demo data: no external API calls from Tool 1
The agent does not have access to the internet, cannot send messages, and cannot modify anything outside of _action_store.
15. Testing Strategy
10 test cases are required for H1-A. All must pass before advancing to H1-B.
| Test | Description | File |
|---|---|---|
| T01 | get_demo_project_context() schema validation |
test_tools.py |
| T02 | create_demo_action() creates valid action |
test_tools.py |
| T03 | Idempotency: same key → same record; different key → new record | test_tools.py |
| T04 | Verification after creation: action present in store | test_tools.py |
| T05 | Event schema, JSON validity, log collection, optional fields | test_execution_events.py |
| T06 | No secret patterns in events | test_execution_events.py |
| T07 | Model is gemini-3.5-flash | test_agent_config.py |
| T08 | Tools registered, correct name, instruction present | test_agent_config.py |
| T09 | Invalid input produces controlled error (not unhandled exception) | test_tools.py |
| T10 | RunConfig.max_llm_calls: ADK default=500; acceptance cap=10 | test_agent_config.py |
The test suite is deterministic and runs without a live Gemini API key. Only the acceptance run (acceptance_run.py) requires GOOGLE_API_KEY.
16. Architecture Decisions
Why LlmAgent and not a custom loop?
ADK’s LlmAgent provides the tool-calling loop, session management, and RunConfig out of the box. Building a custom loop would replicate this infrastructure without adding value at H1-A.
Why temperature 0.2?
Strategic action selection should be deterministic given the same context. Lower temperature reduces variance without eliminating the model’s ability to reason over the opportunity scores.
Why in-memory storage for H1-A?
The goal of H1-A is to validate the agent loop, tool architecture, and test coverage. Introducing a database dependency at this stage would complicate local development and add a failure mode unrelated to the agent logic being tested.
Why idempotency at the tool level (not the agent level)?
Tool-level idempotency is more robust: it works regardless of how the agent instruction changes, and it survives retries and network failures without requiring the model to reason about deduplication.
Why emit events to stdout?
Stdout is the universal integration point for container-based logging. No SDK or library is required. Cloud Run, Cloud Functions, and most container platforms pick up structured stdout automatically.
17. Learnings
Instruction precision matters more than length. Vague instructions produce inconsistent tool-calling sequences. “Create exactly ONE action” is more reliable than “create the most important action.”
Test T10 revealed an ADK behavior worth knowing. max_output_tokens controls per-response token generation, not the number of iterations. The loop guard is RunConfig(max_llm_calls=N) — a separate parameter. Both are needed for different reasons.
Idempotency is underrated in agent design. Most agent tutorials show happy paths. The interesting cases are retries, partial failures, and duplicate runs. Building idempotency in from the start made the acceptance run far easier to verify.
Structured events make debugging fast. Being able to read the exact sequence of events — AGENT_STARTED → CONTEXT_LOADED → PLAN_CREATED → TOOL_STARTED → TOOL_SUCCEEDED → RESULT_VERIFIED → AGENT_COMPLETED — as JSON lines is much cleaner than parsing mixed log output.
18. Limitations (H1-A)
| Limitation | Notes |
|---|---|
| Demo data only | get_demo_project_context() returns hardcoded data. No real project is connected. |
| In-memory storage | Actions are lost when the process exits. |
| Single project | No multi-project or multi-agent orchestration. |
| No Cloud Run deployment | Designed for it; no deployment config in this milestone. |
| One action per run | The instruction enforces exactly one action per execution. |
| No persistent memory across sessions | InMemorySessionService resets each time. |
19. What’s Next (H1-B and Beyond)
H1-B content is not yet defined in the repository. H1-C is labeled as the Supabase integration milestone — connecting real InsightValues project data and persisting actions across sessions.
The tool interface (get_demo_project_context → create_demo_action) is designed to be swapped: the function signatures, validation logic, and event emission remain the same; only the data source and storage backend change.
20. Hackathon Disclosure
This article was created as part of our participation in the All Things Agentic Hackathon 2026.
This submission is a standalone Python agent (the IVE agent), not the full InsightValues platform. The preexisting platform (Flutter/Supabase) is disclosed in the README. The IVE agent was built specifically for this hackathon, during the hackathon period.
The IVE agent repository, all 10 required tests, and the acceptance run are the submission artifacts.
Related: InsightValues: Da Inteligência à Execução — the strategic context behind this technical work.