Building a Survival Gear Diagnostic AI Agent (Alaska-Inspired Extension of AutoDetective)
I built AutoDetective.ai to help people diagnose car problems. Type in your symptoms — weird noise from the engine, check engine light, rough idle — and...
I built AutoDetective.ai to help people diagnose car problems. Type in your symptoms — weird noise from the engine, check engine light, rough idle — and the system walks you through a structured diagnostic flow to figure out what's wrong and what it'll cost to fix.
It works. Over 8,000 pages indexed. Real traffic. Real users getting real answers about their vehicles.
But here's the thing about living in Alaska: your car breaking down is an inconvenience. Your survival gear failing in the backcountry is a life-threatening emergency.
Last fall I was 40 miles up the Susitna River when my water filter started producing cloudy output. Was the filter element degraded? Was the O-ring failing? Was the pre-filter clogged? I knew enough to troubleshoot it in the field, but I thought about all the people who head into the Alaskan wilderness without that knowledge. And I realized the exact same diagnostic pattern I built for automotive problems could work for outdoor and survival equipment.
So I built a prototype. Here's how.
The Diagnostic Pattern: Why It Transfers
The core insight behind AutoDetective isn't AI-specific — it's a structured troubleshooting methodology that happens to be powered by AI. The pattern looks like this:
- User describes a symptom (what they're experiencing)
- System asks clarifying questions (narrowing the problem space)
- System generates a diagnostic tree (possible causes ranked by likelihood)
- System provides actionable steps (what to check, in what order)
- System estimates severity and cost (how urgent, what parts/tools needed)
This is the same pattern a good mechanic uses. It's also the same pattern a good wilderness guide uses when someone's gear is acting up on a multi-day trip.
The difference is domain knowledge. For cars, the system needs to know about engine codes, common failure modes for specific makes and models, and repair procedures. For survival gear, it needs to know about equipment categories, failure signatures, field repair techniques, and when a piece of gear should be retired versus fixed.
The architecture stays the same. The knowledge base changes.
System Architecture
Here's the technical architecture I used for the survival gear diagnostic agent. It's deliberately similar to AutoDetective's architecture because the whole point is that the pattern is reusable.
┌──────────────────────────────────────────────┐
│ Client (Browser) │
│ ┌─────────────────────────────────────────┐ │
│ │ Diagnostic Chat Interface │ │
│ │ - Symptom input │ │
│ │ - Guided Q&A flow │ │
│ │ - Diagnostic results display │ │
│ └─────────────────────────────────────────┘ │
└──────────────┬───────────────────────────────┘
│ REST API
┌──────────────▼───────────────────────────────┐
│ Express.js Server │
│ ┌─────────────┐ ┌───────────────────────┐ │
│ │ Diagnostic │ │ Equipment Knowledge │ │
│ │ Engine │ │ Base │ │
│ │ │ │ - Gear categories │ │
│ │ - Session │ │ - Failure modes │ │
│ │ manager │ │ - Field repair data │ │
│ │ - Flow ctrl │ │ - Safety thresholds │ │
│ └──────┬──────┘ └───────────┬───────────┘ │
│ │ │ │
│ ┌──────▼─────────────────────▼───────────┐ │
│ │ AI Reasoning Layer │ │
│ │ - Prompt construction │ │
│ │ - Response parsing │ │
│ │ - Diagnostic tree generation │ │
│ └─────────────┬───────────────────────────┘ │
└────────────────┼─────────────────────────────┘
│
┌────────────────▼─────────────────────────────┐
│ LLM Provider (Claude API) │
│ Fallback: Local Ollama │
└──────────────────────────────────────────────┘
The key components:
- Diagnostic Engine — Manages the conversation state, decides when to ask follow-up questions, when to generate a diagnosis, and when to escalate to a safety warning
- Equipment Knowledge Base — Structured data about gear categories, common issues, and field repair information
- AI Reasoning Layer — Constructs prompts from the conversation state and knowledge base, sends them to the LLM, and parses structured responses
The Equipment Knowledge Base
The first thing I built was the knowledge base. For AutoDetective, this was car makes, models, and common diagnostic trouble codes. For survival gear, it's equipment categories with their associated failure modes:
var equipmentKnowledge = {
categories: {
'water-filtration': {
name: 'Water Filtration & Purification',
items: ['pump filter', 'gravity filter', 'squeeze filter', 'UV purifier', 'chemical treatment'],
commonSymptoms: [
'slow flow rate',
'cloudy output water',
'pump resistance increased',
'unable to backflush',
'cracked housing',
'O-ring deterioration'
],
safetyLevel: 'critical',
safetyNote: 'Compromised water filtration in the backcountry can cause serious illness. When in doubt, boil water as backup.'
},
'shelter': {
name: 'Shelter & Sleep Systems',
items: ['tent', 'tarp', 'bivy', 'sleeping bag', 'sleeping pad', 'hammock'],
commonSymptoms: [
'tent pole snapped',
'zipper stuck or separating',
'seam leaking',
'pad losing air overnight',
'delamination',
'condensation inside shelter',
'loft loss in sleeping bag'
],
safetyLevel: 'high',
safetyNote: 'Shelter failure in cold conditions can lead to hypothermia. Always carry emergency backup shelter materials.'
},
'navigation': {
name: 'Navigation Equipment',
items: ['GPS unit', 'compass', 'altimeter', 'satellite communicator', 'maps'],
commonSymptoms: [
'GPS not acquiring satellites',
'compass reading erratic',
'barometer readings inconsistent',
'satellite communicator not sending',
'battery drain faster than normal',
'screen damage or failure'
],
safetyLevel: 'critical',
safetyNote: 'Navigation failure in remote areas is a survival emergency. Never rely on a single navigation method.'
},
'stoves-cooking': {
name: 'Stoves & Cooking Systems',
items: ['canister stove', 'liquid fuel stove', 'alcohol stove', 'wood stove', 'cookware'],
commonSymptoms: [
'stove not lighting',
'weak flame or sputtering',
'fuel leak smell',
'pot not sitting stable',
'canister feels full but no flow',
'pump not building pressure',
'clogged jet'
],
safetyLevel: 'high',
safetyNote: 'Fuel leaks are a fire and burn hazard. If you smell fuel, stop immediately and inspect all connections.'
},
'clothing-layers': {
name: 'Clothing & Layer Systems',
items: ['rain shell', 'insulation layer', 'base layer', 'boots', 'gloves', 'gaiters'],
commonSymptoms: [
'waterproofing failed (wetting out)',
'zipper stuck',
'delamination of layers',
'seam tape peeling',
'insulation clumping',
'sole separation',
'DWR coating degraded'
],
safetyLevel: 'medium',
safetyNote: 'Clothing system failure in cold or wet conditions can quickly lead to hypothermia.'
}
}
};
module.exports = equipmentKnowledge;
Notice the safetyLevel field. This is critical. When AutoDetective tells you your brake pads might be worn, that's a safety issue. When a survival gear diagnostic tells you your water filter might be compromised 40 miles from the nearest road, that's a different magnitude of safety issue entirely.
The diagnostic engine uses safety levels to inject appropriate warnings into its responses and to adjust how conservative its recommendations are.
The Diagnostic Engine
The diagnostic engine manages the conversation flow. It's a state machine that tracks where the user is in the diagnostic process and decides what to ask next:
var equipmentKnowledge = require('./equipmentKnowledge');
function DiagnosticSession(sessionId) {
this.sessionId = sessionId;
this.state = 'initial';
this.gearCategory = null;
this.gearItem = null;
this.symptoms = [];
this.context = {};
this.conversationHistory = [];
this.diagnosis = null;
}
DiagnosticSession.prototype.processInput = function(userInput, callback) {
this.conversationHistory.push({
role: 'user',
content: userInput,
timestamp: new Date().toISOString()
});
var self = this;
switch (this.state) {
case 'initial':
this.identifyGearCategory(userInput, function(err, response) {
if (err) return callback(err);
self.state = 'category_identified';
self.addAssistantMessage(response);
callback(null, response);
});
break;
case 'category_identified':
this.collectSymptoms(userInput, function(err, response) {
if (err) return callback(err);
if (self.symptoms.length >= 2) {
self.state = 'collecting_context';
} else {
self.state = 'collecting_symptoms';
}
self.addAssistantMessage(response);
callback(null, response);
});
break;
case 'collecting_symptoms':
this.collectSymptoms(userInput, function(err, response) {
if (err) return callback(err);
self.state = 'collecting_context';
self.addAssistantMessage(response);
callback(null, response);
});
break;
case 'collecting_context':
self.context.additional = userInput;
self.state = 'diagnosing';
self.generateDiagnosis(function(err, response) {
if (err) return callback(err);
self.state = 'complete';
self.addAssistantMessage(response);
callback(null, response);
});
break;
case 'complete':
callback(null, {
message: 'Diagnosis complete. Start a new session for another piece of gear.',
diagnosis: self.diagnosis
});
break;
default:
callback(new Error('Unknown session state: ' + self.state));
}
};
DiagnosticSession.prototype.addAssistantMessage = function(response) {
this.conversationHistory.push({
role: 'assistant',
content: typeof response === 'string' ? response : JSON.stringify(response),
timestamp: new Date().toISOString()
});
};
DiagnosticSession.prototype.identifyGearCategory = function(input, callback) {
var categories = Object.keys(equipmentKnowledge.categories);
var inputLower = input.toLowerCase();
var matched = null;
for (var i = 0; i < categories.length; i++) {
var cat = equipmentKnowledge.categories[categories[i]];
for (var j = 0; j < cat.items.length; j++) {
if (inputLower.indexOf(cat.items[j]) !== -1) {
matched = categories[i];
this.gearCategory = matched;
this.gearItem = cat.items[j];
break;
}
}
if (matched) break;
}
if (matched) {
var catData = equipmentKnowledge.categories[matched];
var response = 'I identified your gear as: **' + this.gearItem +
'** (' + catData.name + ').\n\n';
response += 'What symptoms or problems are you experiencing? Common issues include:\n';
for (var k = 0; k < catData.commonSymptoms.length; k++) {
response += '- ' + catData.commonSymptoms[k] + '\n';
}
callback(null, response);
} else {
callback(null, 'I wasn\'t able to identify the specific gear type. Could you tell me what kind of equipment you\'re having trouble with? For example: tent, water filter, GPS unit, stove, rain shell, sleeping bag, etc.');
}
};
DiagnosticSession.prototype.collectSymptoms = function(input, callback) {
this.symptoms.push(input);
if (this.symptoms.length >= 2) {
callback(null, 'Got it. A couple more questions to help narrow this down:\n\n' +
'1. How old is the gear, and how heavily has it been used?\n' +
'2. When did you first notice the problem?\n' +
'3. Are you currently in the field, or diagnosing at home?');
} else {
callback(null, 'Thanks. Any other symptoms or details about the problem? The more specific you can be, the better the diagnosis.');
}
};
module.exports = DiagnosticSession;
This is intentionally simple. The real intelligence comes from the AI reasoning layer, not the state machine. The state machine just makes sure we gather enough information before asking the LLM to generate a diagnosis.
The AI Reasoning Layer
This is where the magic happens. The reasoning layer constructs a detailed prompt from the session data and asks the LLM to generate a structured diagnosis:
var https = require('https');
var equipmentKnowledge = require('./equipmentKnowledge');
function generateDiagnosisPrompt(session) {
var catData = equipmentKnowledge.categories[session.gearCategory];
var safetyPrefix = '';
if (catData.safetyLevel === 'critical') {
safetyPrefix = 'SAFETY CRITICAL: This equipment category is safety-critical. ' +
'Always err on the side of caution in your recommendations. ' +
catData.safetyNote + '\n\n';
} else if (catData.safetyLevel === 'high') {
safetyPrefix = 'SAFETY NOTE: ' + catData.safetyNote + '\n\n';
}
var prompt = safetyPrefix +
'You are an expert outdoor equipment technician and wilderness guide with ' +
'20 years of experience in Alaska. A user needs help diagnosing a problem ' +
'with their ' + session.gearItem + '.\n\n' +
'SYMPTOMS REPORTED:\n';
for (var i = 0; i < session.symptoms.length; i++) {
prompt += '- ' + session.symptoms[i] + '\n';
}
if (session.context.additional) {
prompt += '\nADDITIONAL CONTEXT: ' + session.context.additional + '\n';
}
prompt += '\nProvide your diagnosis in this exact JSON format:\n' +
'{\n' +
' "primaryDiagnosis": "Most likely cause of the problem",\n' +
' "confidence": "high|medium|low",\n' +
' "possibleCauses": [\n' +
' {\n' +
' "cause": "Description of possible cause",\n' +
' "likelihood": "high|medium|low",\n' +
' "fieldRepairable": true/false,\n' +
' "repairSteps": ["step 1", "step 2"],\n' +
' "partsNeeded": ["part 1", "part 2"],\n' +
' "estimatedCost": "$X-$Y for replacement/repair"\n' +
' }\n' +
' ],\n' +
' "immediateActions": ["What to do right now"],\n' +
' "safetyWarnings": ["Any safety concerns"],\n' +
' "shouldReplace": true/false,\n' +
' "replacementRecommendations": ["Recommended replacement gear if applicable"]\n' +
'}\n\n' +
'Respond ONLY with the JSON object. No additional text.';
return prompt;
}
function callDiagnosticAI(prompt, callback) {
var postData = JSON.stringify({
model: 'claude-sonnet-4-20250514',
max_tokens: 2048,
messages: [{ role: 'user', content: prompt }]
});
var options = {
hostname: 'api.anthropic.com',
port: 443,
path: '/v1/messages',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.ANTHROPIC_API_KEY,
'anthropic-version': '2023-06-01',
'Content-Length': Buffer.byteLength(postData)
}
};
var req = https.request(options, function(res) {
var data = '';
res.on('data', function(chunk) { data += chunk; });
res.on('end', function() {
try {
var response = JSON.parse(data);
var content = response.content[0].text;
var diagnosis = JSON.parse(content);
callback(null, diagnosis);
} catch(e) {
callback(new Error('Failed to parse diagnosis: ' + e.message));
}
});
});
req.on('error', function(err) { callback(err); });
req.write(postData);
req.end();
}
module.exports = {
generateDiagnosisPrompt: generateDiagnosisPrompt,
callDiagnosticAI: callDiagnosticAI
};
The critical design decision here is the safety-first prompt construction. When the gear category is marked as critical — like water filtration or navigation — the prompt explicitly instructs the AI to be conservative. I'd rather have the system tell someone to boil their water unnecessarily than to assure them a compromised filter is fine.
The Express Routes
Wiring it all together with Express follows the same pattern as any other API:
var express = require('express');
var router = express.Router();
var DiagnosticSession = require('../diagnosticSession');
var reasoning = require('../reasoningLayer');
var sessions = {};
router.post('/api/diagnose/start', function(req, res) {
var sessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
var session = new DiagnosticSession(sessionId);
sessions[sessionId] = session;
var gearDescription = req.body.gear || '';
session.processInput(gearDescription, function(err, response) {
if (err) {
return res.status(500).json({ error: err.message });
}
res.json({
sessionId: sessionId,
message: response,
state: session.state
});
});
});
router.post('/api/diagnose/continue', function(req, res) {
var sessionId = req.body.sessionId;
var userInput = req.body.input || '';
if (!sessionId || !sessions[sessionId]) {
return res.status(400).json({ error: 'Invalid or expired session' });
}
var session = sessions[sessionId];
if (session.state === 'diagnosing') {
var prompt = reasoning.generateDiagnosisPrompt(session);
reasoning.callDiagnosticAI(prompt, function(err, diagnosis) {
if (err) {
return res.status(500).json({ error: 'Diagnosis generation failed: ' + err.message });
}
session.diagnosis = diagnosis;
session.state = 'complete';
res.json({
sessionId: sessionId,
diagnosis: diagnosis,
state: session.state
});
});
} else {
session.processInput(userInput, function(err, response) {
if (err) {
return res.status(500).json({ error: err.message });
}
res.json({
sessionId: sessionId,
message: response,
state: session.state
});
});
}
});
router.delete('/api/diagnose/:sessionId', function(req, res) {
delete sessions[req.params.sessionId];
res.json({ success: true });
});
module.exports = router;
Nothing fancy. Stateful sessions stored in memory (you'd want Redis or a database for production), clean REST endpoints, and a clear separation between the conversation management and the AI reasoning.
Real-World Use Cases From the Field
Let me give you three scenarios where this kind of tool would have been genuinely useful, drawn from actual experiences in the Alaskan backcountry:
The Water Filter Incident
I mentioned this at the top. Forty miles up the Susitna, my Katadyn pump filter started producing cloudy water. In the field, I had to mentally run through the diagnostic tree: Is the ceramic element cracked? Is the pre-filter clogged? Is the O-ring seated properly? Am I getting cross-contamination from a dirty output hose?
A diagnostic agent could walk someone through that same tree in two minutes. For someone less experienced, that could be the difference between getting sick from contaminated water and safely continuing their trip.
The Tent Pole Snap
A friend broke a tent pole segment on a September trip in Denali. The wind was picking up, temperature was dropping, and he had to decide: attempt a field repair with the splint from the tent's repair kit, or break camp and try to get back to the trailhead in deteriorating conditions.
The diagnostic flow here is: What kind of break? Clean snap or splintered? Which pole in the frame? Is the shock cord intact? Do you have the repair sleeve? What's the wind forecast? A good diagnostic agent considers all of these factors and gives a confidence level on whether the field repair will hold.
The GPS Battery Drain
My Garmin InReach started draining its battery at three times the normal rate during a winter trip. Turns out the cold was the culprit — lithium batteries lose capacity dramatically below 20 degrees Fahrenheit — but I spent an anxious hour wondering if I had a hardware failure before I figured it out.
A diagnostic agent that knows about cold-weather battery behavior would have asked "What's the ambient temperature?" as its first follow-up question and saved me that anxiety.
Lessons Learned From the Prototype
Building this prototype taught me a few things that apply to any AI diagnostic agent, not just survival gear:
Domain expertise matters more than model capability. A well-structured prompt with good domain knowledge running on Claude Sonnet produces better diagnoses than a lazy prompt running on the most expensive model available. The knowledge base and prompt engineering do the heavy lifting.
Safety-critical domains need guardrails. When the stakes are someone's physical safety, you can't just let the model freestyle. The safety level system and conservative prompting aren't optional — they're the most important part of the architecture.
Structured output is essential. Asking for JSON output and parsing it programmatically means you can build reliable UI flows on top of the diagnosis. Free-form text responses are fine for chatbots but terrible for actionable diagnostic tools.
The pattern is genuinely reusable. I built the automotive version first, then adapted it for survival gear in a weekend. The same pattern could work for home appliances, electronics, bicycles, musical instruments — any domain where structured troubleshooting follows a predictable decision tree.
What's Next
This is still a prototype. I haven't integrated it into AutoDetective.ai yet, though the architecture is designed to make that straightforward. The gear knowledge base needs to be much deeper — I've only scratched the surface of failure modes for each equipment category.
But the core concept is proven: AI-powered diagnostic agents work for any domain where you can define equipment categories, symptom taxonomies, and repair procedures. The pattern transfers cleanly from cars to camping gear to whatever domain you know deeply.
If you're building something similar, steal the architecture. The state machine, the knowledge base structure, the safety-aware prompt construction — these are patterns that work. Adapt the domain knowledge to whatever you're diagnosing, and you've got yourself a useful tool.
And if you happen to be building it from a cabin in Alaska, make sure you test it offline too. You never know when the next snowstorm is coming.
Shane Larson is a software engineer with 30+ years of experience. He builds things at Grizzly Peak Software and AutoDetective.ai from a cabin in Caswell Lakes, Alaska — where diagnosing gear failures is a practical skill, not a theoretical exercise.