# Try it on one laptop

Run Straza and Claude Code on your own computer. A starter rule denies a command, and you approve a held command in the browser.

- Who: You, as the admin, and later as alice
- Where: Four terminals and a browser
- Profile: Standalone

In short: You start the server on your computer, enroll that computer and connect Claude Code. The starter rule denies `rm -rf` at once. A rule you add holds `git push` until you approve it yourself in this browser. The agent's next try within 60 seconds then runs, and the approval covers only that try.


YourunStrazaonyourownmachineasa[person](https://docs.straza.ai/concepts/identities/index.md)namedaliceandgovernherClaudeCode.Thestandaloneprofileincludesitsowndatabase,eventbrokerandsign-inpage,sonothingelsehastorun.A[policy](https://docs.straza.ai/concepts/policy-model/index.md)ruledeniesacommandatonce.Thenaruleyouwriteholdsacommanduntilyou[approve](https://docs.straza.ai/concepts/approvals-model/index.md)it.##Beforeyoustart{.nostep}-ALinuxormacOSmachinewithnoStrazapackageandnomanagedinstall,becauseeitheronemakesevery`straza`commandusethesystemservice.OnWindowstheservicerunsonlyastheWindowsservice,as[Install](https://docs.straza.ai/guides/operate/install/index.md#install-the-service-on-windows)shows.-Thebinaries`strazad`,`strazactl`and`straza`onyourPATH,as[Putthebinariesonyourpath](https://docs.straza.ai/guides/operate/install/index.md#put-the-binaries-on-your-path)shows.-ClaudeCode,abrowseronthismachineandanemptydirectoryfortheserver.##StarttheserverInthefirstterminal,intheemptydirectory,starttheserveronthestandaloneprofile.Onasharednetwork,suchasanofficeoracafé,put`STRAZA_APPROVER_TLS_AUTO_MINT=false`infrontof`strazad`.Thatturnsoffthephoneapprover,whichotherwiselistensonport8443oneveryinterface.Thistutorialapprovesinthebrowserthroughport8420anddoesnotneedit.Terminal1,server,keepitrunning:```shstrazadserve--profilestandalone```Youshouldsee:Thelogsays`strazadserving`at`127.0.0.1:8420`.Aboveitarethepasswordsof`admin`and`break-glass`,andalinethatsaysthestarterpolicydenies`rm-rf`.>Actnow:Savebothpasswordsnow>>Thefirststartprintsthemonce.Arestartofthesamedatadirectorydoesnotprintthemagain.Recordedoutput:Itshowsonlythelinesnamedabove,withthepasswordsmasked.Thewalk'sserverlistenedoneveryaddressofitscontainerandansweredat`http://127.0.0.1:18420`,asthefinalfoldexplains.```text{"level":"WARN","msg":"bootstrapadmincreated.Storethispasswordnow,itwillnotbeshownagain","username":"admin","password":"5861xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}{"level":"INFO","msg":"starterpolicyseeded.Recursiveforce-delete(rm-rf)isdeniedwithareason;editordeletePolicySetstandalone-startertochangethis"}{"level":"WARN","msg":"break-glassadmincreated.Storethispasswordinyourvaultnow,itwillnotbeshownagain;rotateon-boxvia`strazactlusersset-passwordbreak-glass`","username":"break-glass","password":"95c4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}{"level":"INFO","msg":"strazadserving","addr":"[::]:8420","profile":"standalone","publicUrl":"http://127.0.0.1:18420","tls":false,"version":"v1.0.0-1700-g89d0cf1d"}```Theserverkeepsitsstateunder`data`inthatdirectory.ItsconsoleandAPIlistenon127.0.0.1only.[Portsandnetwork](https://docs.straza.ai/reference/ports-and-network/index.md)listseveryporttheserveropens.##SignintotheconsoleOpen`http://127.0.0.1:8420/console/`inyourbrowserandpress**Signin**.OnthepagetitledSignintoStraza,enter`admin`andthesavedpassword.Youshouldsee:TheconsoleopensonOverview.Thebottomofthemenusays`standalone`andtheserver'sbuild.`strazactl`hasnosign-inofitsown,somintitanadminAPItokenhere.Clickpathintheconsole:"Settings"›"APItokens"›"NewAPItoken"Nameit`admin-terminal`.Under**Lifetime**pick`expiresin30days`,under**Thejob**pick**Fullroot**,andpress**Minttoken**.Copythetokennow,becausethesheetshowsitonceandtheserverkeepsonlyitshash.Ifthisfails:`Invalidusernameorpassword.`:Usethe`admin`passwordfromthefirststartofthisdatadirectory.##AddaliceInasecondterminal,passthetokento`strazactl`.Atthe`read`line,pastethetokenandpressEnter,whichkeepsitoffthescreenandoutoftheshellhistory.Thencreatealice,thepersonyouragentworksfor.The[role](https://docs.straza.ai/concepts/roles-and-access/index.md)`straza-enroll-browser`letsherturnabrowserintoanapprovaldevice.Terminal2,administration:```shexportSTRAZA_SERVER=http://127.0.0.1:8420read-rsSTRAZA_API_TOKEN&&exportSTRAZA_API_TOKENstrazactluserscreatealice--password'pick-a-passphrase'strazactlassignstraza-enroll-browser--useralice```Youshouldsee:`createduseralice`withanid,then`assignedstraza-enroll-browsertoalice`.Recordedoutput:```textcreateduseralice(01a19de0-43b0-7327-82a8-d66405f53f36)assignedstraza-enroll-browsertoalice```Whoeverholdsthetokenactsasanadministratoruntilitexpiresoryourevokeit,sokeepitinthisterminalonly.Neverputitinashellprofileoranywhereanagentruns.Ifthisfails:`strazactlneedsanadminAPItokeninSTRAZA_API_TOKEN.`:Runthe`read`lineagaininthisterminalandpastethetoken.##StartthebackgroundserviceThebackgroundservice,`strazaservice`,keepsalice'skeyandeveryStraza[session](https://docs.straza.ai/concepts/machines-and-sessions/index.md)thatrunsonthismachine.With`STRAZA_HOME`set,itrunsasyourownOSuserandkeepsitssocketanditsstateinthatdirectoryinsteadofthesystemlocation.Terminal3,backgroundservice,keepitrunning:```shexportSTRAZA_HOME="$HOME/.straza"strazaservice```Youshouldsee:Aloglinethatsays`strazaservicelistening`,withthesocketpathand`user_mode=true`.##EnrollthismachineasaliceOpenafourthterminalforalice.Itshares`STRAZA_HOME`withtheservicebuthasnotoken,sotheClaudeCodeyoustartherecannotreadthetoken.Terminal4,alice:```shexportSTRAZA_HOME="$HOME/.straza"strazaenroll--serverhttp://127.0.0.1:8420```Yourbrowseropensonthesign-inpage.Signinas`alice`withherpassphrase.ThetabsaysthatyouaresignedintoStrazaonthiscomputer.Youshouldsee:`Enrolledasalice`,theidofthisdevice,andthatthebackgroundserviceholdsthismachine'skey.Theenrollmentlasts7daysfromalice'ssign-in.Afterthattheserverrefusesthismachine'scheck-insuntilsheruns`strazaenroll`again.Ifthisfails:``Straza'sbackgroundserviceforSTRAZA_HOME…isn'trunning``:Start`strazaservice`inTerminal3,andexportthesame`STRAZA_HOME`inbothterminals.`Thismachinehasnodisplay,soStrazacannotopenabrowserhere.`:Add`--use-device-code`,openthelinkitprints,andsigninthereasalice.##ConnectClaudeCodeInTerminal4,installthehooksforyouruser,thenstartClaudeCodeinathrowawaydirectory.Terminal4,alice:```shstrazainstallclaude-codemkdir-p~/straza-try&&cd~/straza-tryclaude```Youshouldsee:`installedStrazahooksforclaude-code`withthesettingspath,thenthebanner`Strazagovernanceactive:alice`whenClaudeCodestarts.AskClaudeCodetorun`rm-rf/tmp/x`.Thestarterruledeniesit,andClaudeCodeshowsthereason,`Strazastarterpolicy:recursiveforce-deleteisdenied.`Acommandthatnorulenames,suchas`gitstatus`,runs.ThesamecallswithoutClaudeCode:ClaudeCoderuns`strazahook`beforeeachtoolcallandreadsitsanswer.TowatchthatwithoutClaudeCode,sendthesameeventsbyhandinTerminal4.Thehookonlyreturnsadecision.```shprintf'%s''{"hook_event_name":"SessionStart","session_id":"laptop-1","cwd":"/tmp"}'|strazahook--harnessclaude-codeprintf'%s''{"hook_event_name":"PreToolUse","session_id":"laptop-1","cwd":"/tmp","tool_name":"Bash","tool_input":{"command":"rm-rf/tmp/x"}}'|strazahook--harnessclaude-code;echo"exit$?"``````text{"hookSpecificOutput":{"additionalContext":"Strazagovernanceisactiveforthissession.Youareoperatingas\"alice\"(roles:straza-enroll-browser)againsthttp://127.0.0.1:18420;policysnapshotc485b47b783a,attestationadvisory.Tooluseischeckedlocallyagainstsignedpolicyandeverydecisionisaudited.Adeniedtoolcallalwayscarriesitsreason:relayittotheuseranddonotretryorworkaroundthedenial.","hookEventName":"SessionStart"},"systemMessage":"🛡Strazagovernanceactive:alice(straza-enroll-browser)@http://127.0.0.1:18420·policyc485b47b783a·attestationadvisory"}{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"Strazastarterpolicy:recursiveforce-deleteisdenied.Deletefilesindividually,oranadmincaneditthestandalone-starterPolicySet."}}Strazastarterpolicy:recursiveforce-deleteisdenied.Deletefilesindividually,oranadmincaneditthestandalone-starterPolicySet.exit2```ClaudeCodereadstheJSONonstandardoutputandshowsyouthereasonlinefromstandarderror.Exitstatus2tellsitnottorunthetool.##HoldgitpushforyourselfArulewiththemode`confirm`holdsacalluntilthepersonthesessionactsforapprovesit.Nobodyelsecanapproveit,anadminincluded.Itguardsagainstanagent'smistakeorapromptinjection.Itdoesnotguardagainstyou.InTerminal2,writetheruleandactivateit.Terminal2,administration:```shcat>confirm-git-push.yaml<<'EOF'apiVersion:straza.dev/v1beta1kind:PolicySetmetadata:name:confirm-git-pushspec:rules:-id:confirm-git-pushtools:[shell.exec]command:allowPatterns:["gitpush*"]effect:allowmode:confirmEOFstrazactlpolicyapply-fconfirm-git-push.yamlstrazactlpolicyactivateconfirm-git-push```Youshouldsee:`appliedconfirm-git-push(Off,…)`,then`publishedconfirm-git-push,itislivenow`withthenewsnapshot.Recordedoutput:```textappliedconfirm-git-push(Off,01a19de0-c0bc-7823-969e-caa9fb285ebc)publishedconfirm-git-push,itislivenow;newsnapshotefb029c325312d809e3fb89379a34283b6d492d45aed4d8500e79df3456dd5b9```TherunningClaudeCodesessionusesthenewrulewithinseconds.Forapersonwithnosponsor,arulewiththemode`approve`thatnamesnoapproverroleholdsthecallthesameway,becausetherequestthengoestothatperson.##TurnonapprovalsinthisbrowserOpen`http://127.0.0.1:8420/self-service/`.Itsays`Signedinasadmin`,becauseitsharestheconsole'ssign-in.Press**Signout**,then**Signin**,andsigninasalice.Open**Thisbrowser**,press**Enablethisbrowser**,keeporchangethename,andpress**Enable**.Thebrowsermakesakeythatneverleavesit.Theserverkeepsonlythepublichalf.Useanormalwindow,sinceaprivatewindowdeletesthekeywhenitcloses.Youshouldsee:`Enabled.Thisbrowserdecidesasalice.`,andonedevicerowforalicemarked`thisbrowser`and`softwarekey`.##Approveyouragent'scallAskClaudeCodetorun`gitpush`.Thehookdeniesitatonce.ClaudeCodeshowsareasonthatstarts`Straza:thiscallneedstherequester'sconfirmation`andendswithareference.Ontheself-servicepage,open**Requests**.Withinafewsecondsarowshows`gitpush`foralice,with`onlytherequesterconfirms`.Press**Approve**,then**Approverequest**.Thedialogsaysthecallrunsnow,butwithClaudeCodeitrunswhentheagentsendsitagain.Within60secondsofyourapproval,askClaudeCodetorun`gitpush`againinthesamesession.Youshouldsee:`Approved.gitpushrunsnowforalice.`inthebrowser,andClaudeCoderunsthecommandonitsnexttry.Atryafterthatneedsanewapproval.ThesamecallswithoutClaudeCode:SendthisinTerminal4forthedenyanditsreference.Afteryouapproveinthebrowser,senditagainfortheallow.```shprintf'%s''{"hook_event_name":"PreToolUse","session_id":"laptop-1","cwd":"/tmp","tool_name":"Bash","tool_input":{"command":"gitpush"}}'|strazahook--harnessclaude-code;echo"exit$?"``````textStraza:thiscallneedstherequester'sconfirmation,ontheirenrolledphone,ortheself-servicepageunderThisbrowser(http://127.0.0.1:18420/self-service/);retryafteritisconfirmed(ref01a19de1-3f04-73a3-8a89-46c524213da7){"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"Straza:thiscallneedstherequester'sconfirmation,ontheirenrolledphone,ortheself-servicepageunderThisbrowser(http://127.0.0.1:18420/self-service/);retryafteritisconfirmed(ref01a19de1-3f04-73a3-8a89-46c524213da7)"}}exit2```Onesecondaftertheapproval,thesamecommandwasallowed.```text{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}exit0```Athirdsendgotanewreference,`01a19de1-76cc-7543-991c-80ddacfc5eff`,becausetheapprovalhadbeenused.Ifthisfails:NorowunderRequests,ortherowisgone:Arequestwaits90secondsforyourapprovalandthenexpires.AskClaudeCodetorunthecommandagain,whichopensanewrequest.##ReadtherecordEverystepaboveleftarecordonthe[auditchain](https://docs.straza.ai/concepts/evidence/index.md),whereeachrecordislinkedtotheonebeforeitbyahash.InTerminal2,readthenewestfiveandcheckthechain.Terminal2,administration:```shstrazactlaudittail--limit5strazactlauditverify```Youshouldsee:Therequest,thedenywithitsreference,alice'sapprovalfromherbrowser,itsuse,andtheallowed`gitpush`with`confirmedbyalice`.Then`auditchainintact:`andacount.Recordedoutput:Eachrecordistrimmed.Therealonesalsocarrytheidsofthesession,theuser,thesnapshotandtherecord,plusthesourceandthetime.```text#14[alice]{"data":{"approvalId":"01a19de1-3f04-73a3-8a89-46c524213da7","lane":"hook","phase":"request","rule":"confirm-git-push","state":"pending","summary":"shell.exec:gitpush"},"type":"straza.audit.approval"}#15[alice]{"data":{"command":"gitpush","effect":"deny","event":"tool.pre","harness":"claude-code","ruleId":"confirm-git-push","tool":"shell.exec"},"type":"straza.audit.tool"}#16[alice]{"data":{"approvalId":"01a19de1-3f04-73a3-8a89-46c524213da7","channel":"browser","decidedDeviceId":"apd_01a19de1-0cd4-7200-9af5-ca482bc3d1a2","lane":"hook","phase":"resolution","state":"approved"},"type":"straza.audit.approval"}#17[alice]{"data":{"approvalId":"01a19de1-3f04-73a3-8a89-46c524213da7","consumedAt":"2026-11-02T20:09:09Z","lane":"hook","phase":"consumed","state":"approved"},"type":"straza.audit.approval"}#18[alice]{"data":{"command":"gitpush","effect":"allow","event":"tool.pre","harness":"claude-code","reason":"Straza:confirmedbyalice(ref01a19de1-3f04-73a3-8a89-46c524213da7)","ruleId":"confirm-git-push","tool":"shell.exec"},"type":"straza.audit.tool"}auditchainintact:18recordsverified```Whenyouaredone,findthetoken'sidwith`strazactlapi-tokenlist`andrevokeitwith`strazactlapi-tokenrevoke`andthatid.##RemoveStrazafromthismachineRemovethehooksfirst,whiletheservicestillruns.Iftheservicestopswhilethehooksareinstalled,ClaudeCodecanrunnotool,becausethehookdenieseverycallwith`Straza'sbackgroundserviceforSTRAZA_HOME…isn'trunning`.Terminal4,alice:```shstrazauninstallclaude-code```Youshouldsee:`removedStrazahooksforclaude-code`and`removedStrazaMCPserverforclaude-code`,eachwiththefileitchanged.ThenpressCtrl+CinTerminal3tostoptheserviceandinTerminal1tostoptheserver.Deletealice'skeyandtheservice'sstate,andthedirectoryClaudeCodeworkedin.Terminal4,alice:```shrm-rf"$HOME/.straza"~/straza-try```Last,deletethedirectoryyoustartedtheserverin.Itholdstheserver'sdata,theusersandtheadmintokenincluded.##Whatthisprotectsononelaptop{.nostep}Theconfirmrulecatchesamistakebytheagent,andapromptinjectionthatasksforacommandyoudidnotmean.Theagentcannotapproveitsowncall,becauseasessionthatacodingtoolcheckedincanneverdecidearequest.Itdoesnotstopyou,becauseyouaretheonewhoapproves.Ahookinstalledforyouruseronlyadvises,soanagentthatcanrunanycommandcanbypassit.Startedbyhand,theservicerunsasyou,soanyprogramyouruncanreadalice'skey,includingtheagent.Anagentthatcanreadyoursign-incouldalsoenrollanapprovaldeviceofitsown.[Knownlimits](https://docs.straza.ai/security/known-limits/index.md)hasarowforeachofthelastthree,and[Thesecuritymodel](https://docs.straza.ai/evaluate/security-model/index.md)showswhereStrazaenforcesaboundary.Howthispagewaswalked:EveryterminalstepraninafreshAlpine3.20containeronLinuxamd64,asanordinaryuser,withthebinariesbuiltatv1.0.0-1700-g89d0cf1d.ThebrowserstepsraninheadlessChromiumonthehost.Forthehost'sbrowsertoreachtheserver,`strazad`ranwith`--listen:8420`,soitlistenedoneveryaddressofthecontainer.Thecontainer'sport8420waspublishedonthehostas127.0.0.1:18420,and`STRAZA_PUBLIC_URL`wassetto`http://127.0.0.1:18420`,sosign-inpagesandlinksnamedtheaddressthebrowsercouldreach.Asocatforwardmadethataddressanswerinsidethecontainertoo.Everycommandthereforeused`http://127.0.0.1:18420`wherethispagesays`http://127.0.0.1:8420`.Thecontainerhasnodisplay,so`strazaenroll`ranwith`--use-device-code`,andalicesignedinonthecodepageinthebrowser.`strazainstallclaude-code`andClaudeCodeitselfdidnotrun.Eachcalloftheagentwentto`strazahook--harnessclaude-code`byhand,asthefoldsaboveshow.TheadminAPItokenwasmintedintheconsoleandreached`strazactl`throughthe`read`lineaswritten.Theserverstartwiththephoneapproveroffandtheremovalstepsranon2026-11-03inafreshcontainerofthesamekind,withthebinariesbuiltatv1.0.0-1709-gacba8249.With`STRAZA_APPROVER_TLS_AUTO_MINT=false`,nothinglistenedonport8443,andport8420stillservedtheapproverroutesandtheself-servicepage.`strazainstallclaude-code`and`strazauninstallclaude-code`ranforthecontainer'sownuser.Withtheservicestopped,`gitstatus`sentto`strazahook`camebackdeniedwithexitstatus2.Inanearlierwalkonthesamebuild,aretry62secondsaftertheapprovalaskedagain,andanapproverulewithnoapproverroleheldalice'scallasherownconfirmrequest.Next:[Holdacallforaperson](https://docs.straza.ai/guides/write-policy/hold-for-a-human/index.md)


Walked on v1.0.0-1700-g89d0cf1d on 2026-11-02, except Claude Code itself, whose calls went to straza hook by hand, and the enroll browser sign-in, done by device code. Walked in a fresh Alpine 3.20 container on Linux amd64, with the browser steps in headless Chromium.

