diff --git a/.envrc.example b/.envrc.example
new file mode 100644
index 0000000..a11fff1
--- /dev/null
+++ b/.envrc.example
@@ -0,0 +1,5 @@
+PATH_add .
+
+# for git-changelog (https://github.com/dannyben/git-changelog)
+export CHANGELOG_COMMIT_URL=https://github.com/DannyBen/opcode/commit/%h
+export CHANGELOG_COMPARE_URL=https://github.com/dannyben/opcode/compare/%s
\ No newline at end of file
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index c896489..4b39373 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -49,8 +49,8 @@ jobs:
     steps:
     - name: Checkout code
       uses: actions/checkout@v4
-    - name: Upgrade the outdated bash
-      run: brew install bash
+    - name: Upgrade the outdated bash and install completions
+      run: brew install bash bash-completion
     - name: Run setup
       run: ./setup
     - name: Test setup artifacts
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2f49a11..ab08aa4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,49 +1,64 @@
-Change Log
+Changelog
 ========================================
 
+v1.0.0 - 2024-05-14
+----------------------------------------
+
+- Add support for clean multiline commands (auto-joined with &&) [`9a46eb5`](https://github.com/DannyBen/opcode/commit/9a46eb5)
+- Fix completions setup for mac [`7ecdaba`](https://github.com/DannyBen/opcode/commit/7ecdaba)
+- Compare [`v0.6.5..v1.0.0`](https://github.com/dannyben/opcode/compare/v0.6.5..v1.0.0)
+
+
 v0.6.5 - 2024-03-08
 ----------------------------------------
 
-- Add color functions for use in op.conf
+- Add color functions for use in op.conf [`926708c`](https://github.com/DannyBen/opcode/commit/926708c)
+- Compare [`v0.6.4..v0.6.5`](https://github.com/dannyben/opcode/compare/v0.6.4..v0.6.5)
 
 
 v0.6.4 - 2023-03-12
 ----------------------------------------
 
-- Fix inability to use a one character command
-- Normalize with shfmt and shellcheck
+- Fix inability to use a one character command [`07b777f`](https://github.com/DannyBen/opcode/commit/07b777f)
+- Normalize with shfmt and shellcheck [`73bbd07`](https://github.com/DannyBen/opcode/commit/73bbd07)
+- Compare [`v0.6.3..v0.6.4`](https://github.com/dannyben/opcode/compare/v0.6.3..v0.6.4)
 
 
 v0.6.3 - 2022-11-10
 ----------------------------------------
 
-- Add private commands
+- Add private commands [`bf40d7b`](https://github.com/DannyBen/opcode/commit/bf40d7b)
+- Compare [`v0.6.2..v0.6.3`](https://github.com/dannyben/opcode/compare/v0.6.2..v0.6.3)
 
 
 v0.6.2 - 2022-11-05
 ----------------------------------------
 
-- Enable bash completions for 'op -w' as well
-- Allow running 'op -w' without code to see all codes and commands
+- Enable bash completions for 'op -w' as well [`16e0aac`](https://github.com/DannyBen/opcode/commit/16e0aac)
+- Allow running 'op -w' without code to see all codes and commands [`0e6c3fd`](https://github.com/DannyBen/opcode/commit/0e6c3fd)
+- Compare [`v0.6.1..v0.6.2`](https://github.com/dannyben/opcode/compare/v0.6.1..v0.6.2)
 
 
 v0.6.1 - 2022-11-04
 ----------------------------------------
 
-- Prefer exact match over partial match commands
+- Prefer exact match over partial match commands [`b04877d`](https://github.com/DannyBen/opcode/commit/b04877d)
+- Compare [`v0.6.0..v0.6.1`](https://github.com/dannyben/opcode/compare/v0.6.0..v0.6.1)
 
 
 v0.6.0 - 2021-05-04
 ----------------------------------------
 
-- Remove bashcompinit from zsh autocompletion
-- Change autocomplete installation
+- Remove bashcompinit from zsh autocompletion [`c478257`](https://github.com/DannyBen/opcode/commit/c478257)
+- Change autocomplete installation [`f1a104d`](https://github.com/DannyBen/opcode/commit/f1a104d)
+- Compare [`v0.5.2..v0.6.0`](https://github.com/dannyben/opcode/compare/v0.5.2..v0.6.0)
 
 
 v0.5.2 - 2020-10-26
 ----------------------------------------
 
-- Change setup script to be non-interactive (for CI)
-- Update setup script to avoid installing autocomplete if there is no ~/.bashrc
+- Change setup script to be non-interactive (for CI) [`aa3b16f`](https://github.com/DannyBen/opcode/commit/aa3b16f)
+- Update setup script to avoid installing autocomplete if there is no ~/.bashrc [`e395bbc`](https://github.com/DannyBen/opcode/commit/e395bbc)
+- Compare [`v0.5.1..v0.5.2`](https://github.com/dannyben/opcode/compare/v0.5.1..v0.5.2)
 
 
diff --git a/README.md b/README.md
index a7e710b..2f729a3 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
 
 # Opcode - Local Command Shortcuts
 
-![Version](https://img.shields.io/badge/version-0.6.5-blue.svg)
+![Version](https://img.shields.io/badge/version-1.0.0-blue.svg)
 ![Test](https://github.com/DannyBen/opcode/workflows/Test/badge.svg)
 
 </div>
@@ -158,12 +158,38 @@ pull
 
 ## Multiline Commands
 
-You may split your command to multiple lines by ending the line with a
-backslash, and indenting the subsequent lines by at least one space:
+In order to specify multiple commands for a single code, provide the commands
+indented with one or more spaces immediately under the command code:
 
 ```shell
-up: docker-compose build && \
-    docker-compose up web
+up:
+  docker compose build
+  docker compose up web
+```
+
+Note that these commands will be joined together with `&&` - so the above 
+will be converted to:
+
+```shell
+docker compose build && docker compose up web
+```
+
+## Concatenated Lines
+
+In case you wish to split your command to multiple lines without joining the 
+lines with `&&`, you can add escape the newline by using `\` (backslash):
+
+```shell
+concat: echo who \
+  ordered \
+  this \
+  pizza
+```
+
+Using this syntax will generate this command:
+
+```shell
+echo who ordered this pizza
 ```
 
 ## Private Commands
diff --git a/doc/op.1 b/doc/op.1
index 15ccaf9..6f1b22a 100644
--- a/doc/op.1
+++ b/doc/op.1
@@ -1,6 +1,6 @@
 .\" Automatically generated by Pandoc 3.1.9
 .\"
-.TH "op" "1" "March 2024" "Version 0.6.5" "local command shortcuts"
+.TH "op" "1" "May 2024" "Version 1.0.0" "local command shortcuts"
 .SH NAME
 \f[B]op\f[R] - local command shortcuts
 .SH SYNOPSIS
@@ -137,12 +137,38 @@ clean: rm tmp/*
 build: docker build
 .EE
 .SS Multiline Commands
-You may split your command to multiple lines by ending the line with a
-backslash, and indenting the subsequent lines by at least one space:
+In order to specify multiple commands for a single code, provide the
+commands indented with one or more spaces immediately under the command
+code:
 .IP
 .EX
-up: docker-compose build && \[rs]
-    docker-compose up web
+up:
+  docker compose build
+  docker compose up web
+.EE
+.PP
+Note that these commands will be joined together with \f[B]&&\f[R] - so
+the above will be converted to:
+.IP
+.EX
+docker compose build && docker compose up web
+.EE
+.SS Concatenated Lines
+In case you wish to split your command to multiple lines without joining
+the lines with \f[B]&&\f[R], you can add escape the newline by using
+\f[B]\[rs]\f[R] (backslash):
+.IP
+.EX
+concat: echo who \[rs]
+  ordered \[rs]
+  this \[rs]
+  pizza
+.EE
+.PP
+Using this syntax will generate this command:
+.IP
+.EX
+echo who ordered this pizza
 .EE
 .SH PARTIAL COMMAND MATCHING
 When running a command, opcode will first try to find an exact match.
diff --git a/doc/op.md b/doc/op.md
index 75da6ba..6f440f9 100644
--- a/doc/op.md
+++ b/doc/op.md
@@ -158,12 +158,38 @@ build: docker build
 
 ## Multiline Commands
 
-You may split your command to multiple lines by ending the line with a
-backslash, and indenting the subsequent lines by at least one space:
+In order to specify multiple commands for a single code, provide the commands
+indented with one or more spaces immediately under the command code:
 
 ```shell
-up: docker-compose build && \
-    docker-compose up web
+up:
+  docker compose build
+  docker compose up web
+```
+
+Note that these commands will be joined together with **&&** - so the above 
+will be converted to:
+
+```shell
+docker compose build && docker compose up web
+```
+
+## Concatenated Lines
+
+In case you wish to split your command to multiple lines without joining the 
+lines with **&&**, you can add escape the newline by using **\\** (backslash):
+
+```shell
+concat: echo who \
+  ordered \
+  this \
+  pizza
+```
+
+Using this syntax will generate this command:
+
+```shell
+echo who ordered this pizza
 ```
 
 
diff --git a/op b/op
index b4c1319..b87a9d3 100755
--- a/op
+++ b/op
@@ -47,10 +47,14 @@ opcode_context() {
     fi
   }
 
+  abort() {
+    echo "$1" >&2
+    exit "${2:-1}"
+  }
+
   need_config() {
     if [[ ! -f $CONFIG_FILE ]]; then
-      echo "Cannot find config file ($CONFIG_FILE)"
-      exit 1
+      abort "Cannot find config file ($CONFIG_FILE)"
     fi
   }
 
@@ -63,28 +67,63 @@ opcode_context() {
       exit 1
     fi
 
-    exact="^${CODE}:[[:space:]]*(.+)$"
-    fuzzy="^${CODE}[^\:]*:[[:space:]]*(.+)$"
+    COMMAND=$(get_command_from_file "exact")
+    if [[ -z $COMMAND ]]; then
+      COMMAND=$(get_command_from_file "fuzzy")
+    fi
+  }
 
-    # shellcheck disable=SC2162
-    while IFS= read line || [ -n "$line" ]; do
-      if [[ $line =~ $exact ]]; then
-        COMMAND="${BASH_REMATCH[1]}"
-        break
-      fi
-    done <"$CONFIG_FILE"
+  get_command_from_file() {
+    local pattern
 
-    if [[ -n "$COMMAND" ]]; then
-      return
+    if [[ $1 == "fuzzy" ]]; then
+      pattern="^${CODE}[^:]*:[[:space:]]*(.*)$"
+    else
+      pattern="^${CODE}:[[:space:]]*(.*)$"
     fi
 
-    # shellcheck disable=SC2162
-    while IFS= read line || [ -n "$line" ]; do
-      if [[ $line =~ $fuzzy ]]; then
-        COMMAND="${BASH_REMATCH[1]}"
-        break
+    local command=""
+    local collect_command=false
+    local temp_line=""
+
+    while IFS= read -r line || [[ -n $line ]]; do
+      if [[ -n "$temp_line" ]]; then
+        trimmed_line=${line#"${line%%[![:space:]]*}"}
+        temp_line="${temp_line%\\}$trimmed_line"
+        if [[ "$line" =~ \\$ ]]; then
+          continue
+        else
+          line="$temp_line"
+          temp_line=""
+        fi
+      fi
+
+      if [[ "$line" =~ \\$ ]]; then
+        trimmed_line=${line#"${line%%[![:space:]]*}"}
+        temp_line="${temp_line%\\}$trimmed_line"
+        continue
+      fi
+
+      if $collect_command; then
+        if [[ -z "${line}" || ! "${line}" =~ ^[[:space:]]+ ]]; then
+          break
+        fi
+
+        trimmed_line="${line#"${line%%[![:space:]]*}"}"
+        command="${command:+$command && }$trimmed_line"
+      else
+        if [[ $line =~ $pattern ]]; then
+          command="${BASH_REMATCH[1]}"
+          if [[ -n $command ]]; then
+            break
+          fi
+
+          collect_command=true
+        fi
       fi
     done <"$CONFIG_FILE"
+
+    echo "$command"
   }
 
   run_command() {
@@ -97,8 +136,7 @@ opcode_context() {
         eval "$COMMAND" "$@"
       fi
     else
-      echo "Code not found: $CODE"
-      exit 1
+      abort "Code not found: $CODE"
     fi
   }
 
@@ -135,7 +173,7 @@ opcode_context() {
 
   list_codes() {
     need_config
-    regex="^([^#:]+):"
+    regex="^([a-zA-Z0-9_-]+):"
     break_regex="^[[:space:]]*private[[:space:]]*$"
 
     # shellcheck disable=SC2162
@@ -151,7 +189,7 @@ opcode_context() {
 
   list_codes_extended() {
     need_config
-    regex="^([^#:]+):"
+    regex="^([a-zA-Z0-9_-]+):"
     comment_regex="^#\? ?(.*)"
     break_regex="^[[:space:]]*private[[:space:]]*$"
 
@@ -199,8 +237,7 @@ opcode_context() {
         # shellcheck disable=SC2086
         echo $COMMAND
       else
-        echo "Code not found: $CODE"
-        exit 1
+        abort "Code not found: $CODE"
       fi
 
     fi
@@ -270,7 +307,7 @@ opcode_context() {
   bold() { printf "\e[1m%b\e[0m\n" "$*"; }
 
   opcode_initialize() {
-    VERSION="0.6.5"
+    VERSION="1.0.0"
     LONG_USAGE=false
     set_config_file
     set -e
diff --git a/op.conf b/op.conf
index d01f63d..a1f9350 100644
--- a/op.conf
+++ b/op.conf
@@ -1,16 +1,25 @@
-test: op approvals && op shellcheck && op shfmt
+test:
+  op approvals
+  op shellcheck
+  op shfmt
 #? Run all tests
 
 approvals: test/approve
 #? Run approval tests
 
-shellcheck: shellcheck op setup && green "PASS: shellcheck"
+shellcheck:
+  shellcheck op setup
+  green "PASS: shellcheck"
 #? Run approval tests
 
-shfmt: shfmt -ci -i 2 -d op setup && green "PASS: shfmt"
+shfmt:
+  shfmt -ci -i 2 -d op setup
+  green "PASS: shfmt"
 #? Run shfmt tests
 
-spell: codespell && green "PASS: codespell"
+spell:
+  codespell
+  green "PASS: codespell"
 #? Run spell checker
 
 man-show: op man | man -l
@@ -19,18 +28,19 @@ man-show: op man | man -l
 man-save: op man > doc/op.1
 #? Convert the markdown man page to man
 
-version: \
-  sed -i "s/$(op --version)/$1/g" op README.md doc/op.md && \
-  op man-save && \
-  git commit -am "version bump $1" && \
+version:
+  [[ -n $1 ]] || abort 'Usage: op version NEW_VERSION'
+  sed -i "s/$(op --version)/$1/g" op README.md
+  op man-save
+  git commit -am "version bump $1"
   git tag v$1
 #? Update version, regenerate and tag
-#? usage: op version NEW_VERSION
+#? Usage: op version NEW_VERSION
 
 private
 
-man: \
-  export DATE=$(date "+%B %Y") && \
-  export VERSION=$(op --version) && \
+man:
+  export DATE=$(date "+%B %Y")
+  export VERSION=$(op --version)
   envsubst <doc/op.md |pandoc -f markdown-smart -s --to man 
 #? Generate man to stdout after substituting template vars
diff --git a/setup b/setup
index 3bd07cd..6c999af 100755
--- a/setup
+++ b/setup
@@ -54,6 +54,8 @@ install_completions() {
     compdir="/usr/share/bash-completion/completions"
   elif [[ -d "/usr/local/etc/bash_completion.d" ]]; then
     compdir="/usr/local/etc/bash_completion.d"
+  elif command -v brew &> /dev/null && [[ -d "$(brew --prefix)/etc/bash_completion.d" ]]; then
+    compdir="$(brew --prefix)/etc/bash_completion.d"
   else
     compdir=''
   fi
diff --git a/test/execute_spec.sh b/test/execute_spec.sh
index f829675..fbb0527 100755
--- a/test/execute_spec.sh
+++ b/test/execute_spec.sh
@@ -56,7 +56,12 @@ describe "op <command>"
 
   context "with multiline config"
     cd ./fixtures/multiline
-    approve "op who"
+    approve "op multi"
+    cd ../../
+
+  context "with concatenated config"
+    cd ./fixtures/multiline
+    approve "op concat"
     cd ../../
 
   context "with a private command"
diff --git a/test/fixtures/empty-dir/approvals/op_help b/test/fixtures/empty-dir/approvals/op_help
index 0597e0a..dafb8f4 100644
--- a/test/fixtures/empty-dir/approvals/op_help
+++ b/test/fixtures/empty-dir/approvals/op_help
@@ -1,4 +1,4 @@
-opcode 0.6.5 - local command shortcuts
+opcode 1.0.0 - local command shortcuts
 
 Usage:
   op CODE [ARGS]
diff --git a/test/fixtures/empty-dir/approvals/op_version b/test/fixtures/empty-dir/approvals/op_version
index ef5e445..3eefcb9 100644
--- a/test/fixtures/empty-dir/approvals/op_version
+++ b/test/fixtures/empty-dir/approvals/op_version
@@ -1 +1 @@
-0.6.5
+1.0.0
diff --git a/test/fixtures/multiline/approvals/op b/test/fixtures/multiline/approvals/op
index 475224e..a551ead 100644
--- a/test/fixtures/multiline/approvals/op
+++ b/test/fixtures/multiline/approvals/op
@@ -1 +1 @@
-why   who   what   
+one   multi   concat   advanced-multi   two   
diff --git a/test/fixtures/multiline/approvals/op_ b/test/fixtures/multiline/approvals/op_
new file mode 100644
index 0000000..d391df1
--- /dev/null
+++ b/test/fixtures/multiline/approvals/op_
@@ -0,0 +1,13 @@
+
+[32mone[0m
+
+[32mmulti[0m
+  these lines will be joined with &&
+
+[32mconcat[0m
+  these lines will be joined without any glue
+
+[32madvanced-multi[0m
+  this will abort unless it gets an argument
+
+[32mtwo[0m
diff --git a/test/fixtures/multiline/approvals/op_who b/test/fixtures/multiline/approvals/op_concat
similarity index 100%
rename from test/fixtures/multiline/approvals/op_who
rename to test/fixtures/multiline/approvals/op_concat
diff --git a/test/fixtures/multiline/approvals/op_multi b/test/fixtures/multiline/approvals/op_multi
new file mode 100644
index 0000000..ac3b4f5
--- /dev/null
+++ b/test/fixtures/multiline/approvals/op_multi
@@ -0,0 +1,3 @@
+one : two
+three
+four
diff --git a/test/fixtures/multiline/approvals/op_w_who b/test/fixtures/multiline/approvals/op_w_concat
similarity index 100%
rename from test/fixtures/multiline/approvals/op_w_who
rename to test/fixtures/multiline/approvals/op_w_concat
diff --git a/test/fixtures/multiline/approvals/op_w_multi b/test/fixtures/multiline/approvals/op_w_multi
new file mode 100644
index 0000000..793d015
--- /dev/null
+++ b/test/fixtures/multiline/approvals/op_w_multi
@@ -0,0 +1 @@
+echo one : two && echo three && echo four
diff --git a/test/fixtures/multiline/op.conf b/test/fixtures/multiline/op.conf
index 68be4f3..f961ea1 100644
--- a/test/fixtures/multiline/op.conf
+++ b/test/fixtures/multiline/op.conf
@@ -1,8 +1,20 @@
-why: echo why
+one: echo one
 
-who: echo who \
+multi:
+  echo one : two
+  echo three
+  echo four
+#? these lines will be joined with &&
+
+concat: echo who \
   ordered \
   this \
   pizza
+#? these lines will be joined without any glue
+
+advanced-multi:
+  [[ -n $1 ]] || abort 'Please provide an argument'
+  echo "$1"
+#? this will abort unless it gets an argument
 
-what: echo what
\ No newline at end of file
+two: echo two
\ No newline at end of file
diff --git a/test/setup_artifacts b/test/setup_artifacts
index 3751e82..a1adbae 100755
--- a/test/setup_artifacts
+++ b/test/setup_artifacts
@@ -14,6 +14,8 @@ get_comp_dir() {
     echo "/usr/share/bash-completion/completions"
   elif [[ -d "/usr/local/etc/bash_completion.d" ]]; then
     echo "/usr/local/etc/bash_completion.d"
+  elif command -v brew &> /dev/null && [[ -d "$(brew --prefix)/etc/bash_completion.d" ]]; then
+    echo "$(brew --prefix)/etc/bash_completion.d"
   else
     echo ''
   fi
diff --git a/test/usage_comments_spec.sh b/test/usage_comments_spec.sh
index 2c2f3b0..4c98188 100755
--- a/test/usage_comments_spec.sh
+++ b/test/usage_comments_spec.sh
@@ -21,3 +21,8 @@ describe "op ?"
     cd ./fixtures/one-char
     approve "op ?"
     cd ../../
+
+  context "with multiline commands"
+    cd ./fixtures/multiline
+    approve "op ?"
+    cd ../../
diff --git a/test/what_spec.sh b/test/what_spec.sh
index b4db687..3d5c2d6 100755
--- a/test/what_spec.sh
+++ b/test/what_spec.sh
@@ -24,7 +24,12 @@ describe "op --what"
 
   context "with a command that was defined as multiple lines"
     cd ./fixtures/multiline
-    approve "op -w who"
+    approve "op -w multi"
+    cd ../../
+
+  context "with a command that was defined as concatenated line"
+    cd ./fixtures/multiline
+    approve "op -w concat"
     cd ../../
 
   context "with a code that does not exist"
