Upgrade to Pro — share decks privately, control downloads, hide ads and more …

疑似コードによるプロンプト記述、どのくらい正確に実行される?

 疑似コードによるプロンプト記述、どのくらい正確に実行される?

Avatar for kokuyouwind

kokuyouwind

January 12, 2026
Tweet

More Decks by kokuyouwind

Other Decks in Programming

Transcript

  1. $ whoami 黒曜 / @kokuyouwind Leaner Technologies Inc. 所属 Rails

    エンジニア・SRE 普段は名古屋からフルリモート勤務 2
  2. 10

  3. テスト⽅法 Claude Code のカスタムスラッシュコマンドとして 擬似コードプロンプトを実装し、挙動を確認 # Claude Code を起動 $

    claude > /plugin marketplace add kokuyouwind/claude-plugins > /plugin install code-like-prompt@kokuyouwind-plugins # 「⽜乳を1 つ買って。卵があったら6 つお願い」 > /code-like-prompt:01-shopping-request { Milk.stock: 10, Egg.stock: 10 } ⏺ Bought 1 milk. Bought 6 eggs. # シェルから⾮対話モードで直接実⾏ $ claude -p "/code-like-prompt:01-shopping-request { Milk.stock: 10, Egg.stock: 10 }" ⏺ Bought 1 milk. Bought 6 eggs. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 https://github.com/kokuyouwind/claude-plugins/tree/main/plugins/code-like-prompt 16
  4. 実装したコマンドのコード --- description: コード⾵プロンプト例1 ⽜乳ジョーク: 妻の依頼 argument-hint: '{"Milk.stock": number, "Egg.stock":

    number}' --- Emulate the following code internally (without using external tools or interpreter) with environment: $ARGUMENTS Output only what puts() commands would output. Do not show any explanations, code, variables, or other messages. ```ruby # Validate required arguments raise "Required argument 'Milk.stock' is missing" if Milk.stock.nil? raise "Required argument 'Egg.stock' is missing" if Egg.stock.nil? # Shopping logic puts("Bought 1 milk.") if Egg.exists? # Egg.exists? means Egg.stock > 0 puts("Bought 6 eggs.") end ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/01-shopping-request.md?plain=1 17
  5. 実装したコマンドのコード --- description: コード⾵プロンプト例1 ⽜乳ジョーク: 妻の依頼 argument-hint: '{"Milk.stock": number, "Egg.stock":

    number}' --- Emulate the following code internally (without using external tools or interpreter) with environment: $ARGUMENTS Output only what puts() commands would output. Do not show any explanations, code, variables, or other messages. ```ruby # Validate required arguments raise "Required argument 'Milk.stock' is missing" if Milk.stock.nil? raise "Required argument 'Egg.stock' is missing" if Egg.stock.nil? # Shopping logic puts("Bought 1 milk.") if Egg.exists? # Egg.exists? means Egg.stock > 0 puts("Bought 6 eggs.") end ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/01-shopping-request.md?plain=1 「外部ツールを使わずエミュレートする」 これを書かないとインタプリタで コードを実⾏しようとする 18
  6. 実装したコマンドのコード --- description: コード⾵プロンプト例1 ⽜乳ジョーク: 妻の依頼 argument-hint: '{"Milk.stock": number, "Egg.stock":

    number}' --- Emulate the following code internally (without using external tools or interpreter) with environment: $ARGUMENTS Output only what puts() commands would output. Do not show any explanations, code, variables, or other messages. ```ruby # Validate required arguments raise "Required argument 'Milk.stock' is missing" if Milk.stock.nil? raise "Required argument 'Egg.stock' is missing" if Egg.stock.nil? # Shopping logic puts("Bought 1 milk.") if Egg.exists? # Egg.exists? means Egg.stock > 0 puts("Bought 6 eggs.") end ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/01-shopping-request.md ここが疑似コード指示の本体 ( 以降はこの部分のみ表示) 19
  7. 簡単なif ⽂: 実装 # 01-shopping-request.md # 妻の依頼: 卵があったら( 卵を)6 個買って

    puts("Bought 1 milk.") if Egg.exists? puts("Bought 6 eggs.") end # 01-shopping-misunderstanding.md # 夫の理解: 卵があったら( ⽜乳を)6 個買って milk_amount = 1 if Egg.exists? milk_amount = 6 end puts("Bought #{milk_amount} milks.") 1 2 3 4 5 6 7 8 9 10 11 12 13 14 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/01-shopping-request.md 21
  8. 簡単なif ⽂: 実⾏結果 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/01-shopping-request.md?plain=1 # 「⽜乳を1 つ買って。卵があったら( 卵を)6 つお願い」 #

    卵がない > /code-like-prompt:01-shopping-request { Milk.stock: 10, Egg.stock: 0 } ⏺ Bought 1 milk. # 卵がある > /code-like-prompt:01-shopping-request { Milk.stock: 10, Egg.stock: 10 } ⏺ Bought 1 milk. Bought 6 eggs. # 「⽜乳を1 つ買って。卵があったら( ⽜乳を)6 つお願い」 # 卵がない > /code-like-prompt:01-shopping-misunderstanding { Milk.stock: 10, Egg.stock: 0 } ⏺ Bought 1 milk. # 卵がある > /code-like-prompt:01-shopping-misunderstanding { Milk.stock: 10, Egg.stock: 10 } ⏺ Bought 6 milks. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 22
  9. if-if-else indent: 実装 if condition_a: if condition_b: print("foo") else: print("bar")

    1 2 3 4 5 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/02a-dangling-else-outer-indent.md 期待する出⼒: a = b = true なら "foo" を出⼒ a = true かつ b = false なら何も出⼒しない a = false なら b に関わらず "bar" を出⼒ 24
  10. if-if-else indent: 実⾏結果 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/02a-dangling-else-outer-indent.md # a = b = true

    なので foo が出⼒されるべき > /code-like-prompt:02a-dangling-else-outer-indent { condition_a: true, condition_b: true } ⏺ foo # a = true, b = false なので 何も出⼒しないべき > /code-like-prompt:02a-dangling-else-outer-indent { condition_a: true, condition_b: false } ⏺ bar 1 2 3 4 5 6 7 8 9 10 11 12 😣 👍 25
  11. if-if-else block: 実装 if (condition_a) { if (condition_b) { printf("foo");

    } } else { printf("bar"); } 1 2 3 4 5 6 7 C ⾔語で書いて、中括弧でスコープを明示すればいけるかも? https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/02a-dangling-else-outer-block.md 26
  12. if-if-else block: 実⾏結果 # a = b = true なので

    foo が出⼒されるべき > /code-like-prompt:02a-dangling-else-outer-block { condition_a: true, condition_b: true } ⏺ foo # a = true, b = false なので 何も出⼒しないべき > /code-like-prompt:02a-dangling-else-outer-block { condition_a: true, condition_b: false } ⏺ I need to trace through this code with the given values: - condition_a = true - condition_b = false Following the execution: 1. condition_a is not NULL, so no error 2. condition_b is not NULL, so no error 3. condition_a is true, so enter the first if block 4. Inside that block, condition_b is false, so the inner if block is skipped 5. No else clause for the inner if, so nothing happens 6. The outer else clause is not executed because condition_a was true Therefore, no printf() statements are executed, resulting in no output. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/02a-dangling-else-outer-block.md ? 27
  13. if-if-else indent: 実⾏結果2 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/02a-dangling-else-outer-indent.md # a = b = true

    なので foo が出⼒されるべき > /code-like-prompt:02a-dangling-else-outer-indent { condition_a: true, condition_b: true } 出⼒がない場合は() を出⼒ ⏺ foo # a = true, b = false なので 何も出⼒しない( 代わりに () を出⼒する) べき > /code-like-prompt:02a-dangling-else-outer-indent { condition_a: true, condition_b: false } 出⼒がない場合は() を出⼒ ⏺ () 1 2 3 4 5 6 7 8 9 10 11 12 「出⼒がない場合は() を出⼒」という指示を追加 29
  14. nested-if: コード https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/02c-deep-nesting-indent.md if level1: if level2: if level3: print("foo")

    else: if level4: print("bar") else: print("baz") else: if level3: if level4: print("qux") else: print("quux") l 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 4 段ネストの複雑なif 「出⼒がない場合は() を出⼒」という指示あり else: if level2: print("corge") else: if level3: print("grault") else: print("garply") 1 2 3 4 5 6 7 8 31
  15. 条件分岐: 考察 Claude Code は「何も出⼒しない」ことが苦⼿そう 「何も出⼒しない代わりに ~ を出⼒」という指示が有効 else の紐づくif

    が正しく解釈されないことがある Python のインデントよりC の中括弧のほうが得意そう 「出⼒なし」のようなケースを避ければ else の紐づけを間違えることはなさそう 深くネストしても問題なく動作する 33
  16. while: 実装・実⾏結果 count = 0 while count < max_count: print("bar")

    count += 1 print("baz") 1 2 3 4 5 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/03a-for-count.md > /code-like-prompt:03b-while-counter { max_count: 3 } ⏺ bar bar bar baz 1 2 3 4 5 6 👍 35
  17. nested-for: 実装・実⾏結果 for i in range(outer_count): for j in range(inner_count):

    print(f"foo{i}{j}") 1 2 3 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/03a-for-count.md > /code-like-prompt:03f-nested-loops { outer_count: 3, inner_count: 2 } ⏺ foo00 foo01 foo10 foo11 foo20 foo21 1 2 3 4 5 6 7 8 👍 37
  18. each: 実装・実⾏結果 items.each do |item| puts item end 1 2

    3 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/03a-for-count.md > /code-like-prompt:03c-each-collection { items: [hoge, fuga, piyo] } ⏺ hoge fuga piyo 1 2 3 4 5 👍 38
  19. ファイルシステムeach: 実装 Dir.glob(pattern).each do |file| puts file end 1 2

    3 「特定種類のファイルそれぞれに操作」を擬似コードで表現 (Dir.glob がどういう挙動をするかは未指定) https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/03h-filesystem-glob.md 40
  20. ファイルシステムeach: 実⾏結果 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/03h-filesystem-glob.md $ ls test1.md test2.rb test3.c test4.md test5.rb

    $ claude # 外部ツールを許可しないと適当な出⼒を返す /code-like-prompt:03h-filesystem-glob { pattern: *.md } ⏺ README.md # search tools を許可すると正しく動作 > /code-like-prompt:03h-filesystem-glob { pattern: *.md } allow search tools ⏺ I'll emulate this Ruby code with the given pattern *.md. ⏺ Search(pattern: "*.md", path: "/private/tmp/test") ⎿ Found 2 files (ctrl+o to expand) ⏺ test1.md test4.md 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 😣 👍 41
  21. 繰り返し: 考察 for, while, each などは意図通りに動作しやすい ネストしたループも問題なく動作する 数字のカウントアップも適切 Dir.glob#each を内部のsearch

    ツールで代替させるなど、 応⽤的な挙動も可能 ファイルや検索結果に対する操作を明示しやすそう 42
  22. 関数呼び出し: 実装 def calculate_score(base, bonus): if bonus: return base *

    2 else: return base score = calculate_score(base, bonus) if score >= 100: print("Excellent") elif score >= 50: print("Good") else: print("Try again") 1 2 3 4 5 6 7 8 9 10 11 12 13 14 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/06b-function-return.md 44
  23. 関数呼び出し: 実⾏結果 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/06b-function-return.md # bonus なしで50 点以上なので、 Good になるはず >

    /code-like-prompt:06b-function-return { base: 80, bonus: false } ⏺ Good # bonus ありで 50 * 2 = 100 なので、 Excellent になるはず > /code-like-prompt:06b-function-return { base: 50, bonus: true } ⏺ Excellent # bonus にboolean ではなく数値を渡すと… ? > /code-like-prompt:06b-function-return { base: 50, bonus: 1 } ⏺ Excellent > /code-like-prompt:06b-function-return { base: 50, bonus: 0 } ⏺ Good # 0 がfalse, それ以外はtrue として扱われるっぽい 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 👍 💯 45
  24. Record パターンマッチ: 実装 data Record = Record { label ::

    String, value :: Int } deriving (Show, Eq) main :: IO () main = do -- record argument is provided as Record type let record = getRecord "record" case record of Record "foo" v -> putStrLn $ "foo:" ++ show v Record "bar" v | v > 10 -> putStrLn "bar-large" Record "bar" v -> putStrLn "bar-small" Record l _ -> putStrLn $ "other:" ++ l 1 2 3 4 5 6 7 8 9 10 11 12 13 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/04b-structural-match.md 49
  25. Record パターンマッチ: 実⾏結果 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/04b-structural-match.md # `Record "foo" v -> putStrLn

    $ "foo:" ++ show v` に従って、 foo:5 が出て欲しい > /code-like-prompt:04b-structural-match { record: { label: foo, value: 5 } } ⏺ foo:5 # `Record "bar" v | v > 10 -> putStrLn "bar-large"` に従って、bar-large が出て欲 しい > /code-like-prompt:04b-structural-match { record: { label: bar, value: 20 } } ⏺ bar-large # `Record l _ -> putStrLn $ "other:" ++ l` に従って、 other:buzz が出て欲しい > /code-like-prompt:04b-structural-match { record: { label: buzz, value: 5 } } ⏺ other:buzz 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 👍 👍 👍 50
  26. Tree パターンマッチ: 実装 data Tree = Leaf String | Branch

    Tree Tree deriving (Show, Eq) main :: IO () main = do -- tree argument is provided as Tree type let tree = getTree "tree" case tree of Leaf x -> putStrLn $ "leaf:" ++ x Branch (Leaf "foo") (Leaf "bar") -> putStrLn "foo-bar" Branch (Leaf "foo") _ -> putStrLn "foo-any" Branch _ (Leaf "bar") -> putStrLn "any-bar" Branch (Branch _ _) _ -> putStrLn "nested" Branch _ _ -> putStrLn "other" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 51
  27. Tree パターンマッチ: 実⾏結果 # `Leaf x -> putStrLn $ "leaf:"

    ++ x` に従って、 leaf:foo が出て欲しい > /code-like-prompt:04d-nested-match { tree: Leaf "foo" } ⏺ leaf:foo # `Branch (Leaf "foo") _ -> putStrLn "foo-any"` に従って、 foo-any が出て欲しい > /code-like-prompt:04d-nested-match { tree: Branch (Leaf "foo") (Leaf "piyo") } ⏺ foo-any # `Branch (Branch _ _) _ -> putStrLn "nested"` に従って、 nested が出て欲しい > /code-like-prompt:04d-nested-match { tree: Branch (Branch (Leaf "foo") (Leaf "bar")) (Leaf "bar")) ⏺ nested 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 👍 👍 👍 52
  28. 有向グラフ: 実装・実⾏結果 % 有向グラフの定義 % a -> b -> c

    -> d % + - - - - ^ path(a, b). path(b, c). path(c, d). path(a, c). % パスを辿って接続しているかの定義 connected(X, Y) :- path(X, Y). connected(X, Y) :- path(X, Z), connected(Z, Y). % a から接続しているノードを探索(fail で強制バックトラックして全列挙) ?- connected(a, X), write(X), write(' '), fail. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 > /code-like-prompt:07-b-multi-clause ⏺ b c d c d 1 2 3 👍 55
  29. 有向グラフ: 実⾏結果( コメントなし) path(a, b). path(b, c). path(c, d). path(a,

    c). connected(X, Y) :- path(X, Y). connected(X, Y) :- path(X, Z), connected(Z, Y). ?- connected(a, X), write(X), write(' '), fail. 1 2 3 4 5 6 7 8 9 10 # b c d c d が出⼒されてほしいが、実⾏ごとに結果が変わってしまう > /code-like-prompt:07-b-multi-clause ⏺ a b c c d > /code-like-prompt:07-b-multi-clause ⏺ a b c d 1 2 3 4 5 6 😣 56
  30. チャンネル1 段: 実装・実⾏結果 func main() { ch := make(chan string)

    go func() { ch <- "foo" ch <- "bar" }() fmt.Println(<-ch) fmt.Println(<-ch) fmt.Println("baz") } 1 2 3 4 5 6 7 8 9 10 11 12 > /code-like-prompt:05b-channel-sync ⏺ foo bar baz 1 2 3 4 5 👍 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/05b-channel-sync.md 59
  31. チャンネル2 段: 実装 func stage1(out chan<- string) { out <-

    "foo" out <- "bar" close(out) } func stage2(in <-chan string, out chan<- string) { for s := range in { out <- s + "X" } close(out) } func main() { ch1 := make(chan string) ch2 := make(chan string) go stage1(ch1) go stage2(ch1, ch2) for result := range ch2 { fmt.Println(result) } fmt.Println("baz") } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/code-like-prompt/commands/05h-pipeline.md > /code-like-prompt:05h-pipeline ⏺ fooX barX baz 1 2 3 4 5 👍 60
  32. RBS Goose Ruby の型定義を推論するClaude Code カスタムコマンド 型検査ツールのセットアップなども⾃動で実⾏する # プラグインを追加 $

    claude > /plugin marketplace add kokuyouwind/claude-plugins > /plugin install rbs-goose@kokuyouwind-plugins # プロジェクト内の型を推論・ブラッシュアップ > /rbs-goose:run 1 2 3 4 5 6 7 https://github.com/kokuyouwind/claude-plugins/tree/main/plugins/rbs-goose 64
  33. RBS Goose - run.md # First Run Setup unless File.exists?('./rbs_goose.yml')

    follow_instruction(File.join(plugin_base_path, 'commands/setup.md')) return end config = Config.load('./rbs_goose.yml') case config.type_annotation_mode when :inline follow_instruction(File.join(plugin_base_path, 'internal/type_inline.md')) when :file follow_instruction(File.join(plugin_base_path, 'internal/type_file.md')) end 1 2 3 4 5 6 7 8 9 10 11 12 13 14 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/rbs-goose/commands/run.md 65
  34. RBS Goose - setup.md # Setup configurations file = File.copy('templates/rbs_goose.template.yml',

    './rbs_goose.yml') puts(file.contents) until('If there are no problems with the above settings file, please answer yes. If you wish to update the file, please describe the changes.') do file.update_contents end # Setup tools config = Config.load('./rbs_goose.yml') unless gemfile.contain?('rbs') puts('setup rbs...') fetch('https://github.com/soutaro/steep') setup_rbs # ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/rbs-goose/commands/setup.md 66
  35. RBS Goose - type_file.md # Load Documentation fetch('https://github.com/ruby/rbs/blob/master/docs/syntax.md') while (typecheck_command.run.type_errors

    > 0) do fix_type_errors end until (project.signatures.each { it.well_typed? }) do refine_signatures fix_type_errors end 1 2 3 4 5 6 7 8 9 10 https://github.com/kokuyouwind/claude-plugins/blob/main/plugins/rbs-goose/internal/type_file.md 67
  36. カスタムコマンドのテスト https://github.com/kokuyouwind/claude-plugins/blob/main/test/code-like-prompt/test01_test.go // Test01ShoppingRequest tests the 01-shopping-request command func Test01ShoppingRequest(t

    *testing.T) { tests := []TestCase{ { Name: "shopping_request_with_eggs", Command: "/code-like-prompt:01-shopping-request", Args: map[string]interface{}{ "Milk.stock": 5, "Egg.stock": 3, }, ExpectedOutputs: []string{ "Bought 1 milk.", "Bought 6 eggs.", }, }, ... } RunTestCases(t, tests) } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 72
  37. リクエストのキャッシュ 都度リクエストすると費⽤も時間もかさむため、 mitmproxy で同⼀プロンプトのリクエストをキャッシュ ( が、あまり安定していない) https://github.com/kokuyouwind/claude-plugins/tree/main/test/vcr # kokuyouwind/claude-code/test #

    Record mode - always call API and update cache BOOT_VCR_MODE=record go test -v # Replay mode - only use cache (fail on cache miss) BOOT_VCR_MODE=replay go test -v # 標準実⾏で auto なので、⾃動で再⽣・追記される 1 2 3 4 5 6 7 8 73
  38. カスタムコマンドのテスト Tips ⾮対話モードの claude -p で実⾏した結果を検査する /tmp 以下など、 CLAUDE.md のないディレクトリで実⾏

    ユーザーやプロジェクトの CLAUDE.md が テスト時に紛れ込むと安定せずコストも上がる haiku で⼗分なら haiku にすると実⾏コストが安くなる claude --model オプションで指定 74