diff --git a/CHANGELOG.md b/CHANGELOG.md
index c35a182b..da3d0751 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@
     * The `with_argparser` decorators now add the Statement object created when parsing the command line to the
     `argparse.Namespace` object they pass to the `do_*` methods. It is stored in an attribute called `__statement__`.
     This can be useful if a command function needs to know the command line for things like logging.
+    * Added a `-t` option to the `load` command for automatically generating a transcript based on a script file
 * Potentially breaking changes
     * The following commands now write to stderr instead of stdout when printing an error. This will make catching
     errors easier in pyscript.
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 33cfe3fc..0aaeb4c3 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -3350,18 +3350,22 @@ class Cmd(cmd.Cmd):
             for hi in history:
                 self.poutput(hi.pr(script=args.script, expanded=args.expanded, verbose=args.verbose))
 
-    def _generate_transcript(self, history: List[HistoryItem], transcript_file: str) -> None:
+    def _generate_transcript(self, history: List[Union[HistoryItem, str]], transcript_file: str) -> None:
         """Generate a transcript file from a given history of commands."""
-        # Save the current echo state, and turn it off. We inject commands into the
-        # output using a different mechanism
         import io
+        # Validate the transcript file path to make sure directory exists and write access is available
+        transcript_path = os.path.abspath(os.path.expanduser(transcript_file))
+        transcript_dir = os.path.dirname(transcript_path)
+        if not os.path.isdir(transcript_dir) or not os.access(transcript_dir, os.W_OK):
+            self.perror("{!r} is not a directory or you don't have write access".format(transcript_dir),
+                        traceback_war=False)
+            return
 
+        # Disable echo while we manually redirect stdout to a StringIO buffer
         saved_echo = self.echo
+        saved_stdout = self.stdout
         self.echo = False
 
-        # Redirect stdout to the transcript file
-        saved_self_stdout = self.stdout
-
         # The problem with supporting regular expressions in transcripts
         # is that they shouldn't be processed in the command, just the output.
         # In addition, when we generate a transcript, any slashes in the output
@@ -3397,10 +3401,9 @@ class Cmd(cmd.Cmd):
             # and add the regex-escaped output to the transcript
             transcript += output.replace('/', r'\/')
 
-        # Restore stdout to its original state
-        self.stdout = saved_self_stdout
-        # Set echo back to its original state
+        # Restore altered attributes to their original state
         self.echo = saved_echo
+        self.stdout = saved_stdout
 
         # finally, we can write the transcript out to the file
         try:
@@ -3456,9 +3459,20 @@ class Cmd(cmd.Cmd):
     load_description = ("Run commands in script file that is encoded as either ASCII or UTF-8 text\n"
                         "\n"
                         "Script should contain one command per line, just like the command would be\n"
-                        "typed in the console.")
+                        "typed in the console.\n"
+                        "\n"
+                        "It loads commands from a script file into a queue and then the normal cmd2\n"
+                        "REPL resumes control and executes the commands in the queue in FIFO order.\n"
+                        "If you attempt to redirect/pipe a load command, it will capture the output\n"
+                        "of the load command itself, not what it adds to the queue.\n"
+                        "\n"
+                        "If the -r/--record_transcript flag is used, this command instead records\n"
+                        "the output of the script commands to a transcript for testing purposes.\n"
+                        )
 
     load_parser = ACArgumentParser(description=load_description)
+    setattr(load_parser.add_argument('-t', '--transcript', help='record the output of the script as a transcript file'),
+            ACTION_ARG_CHOICES, ('path_complete',))
     setattr(load_parser.add_argument('script_path', help="path to the script file"),
             ACTION_ARG_CHOICES, ('path_complete',))
 
@@ -3492,11 +3506,16 @@ class Cmd(cmd.Cmd):
             # command queue. Add an "end of script (eos)" command to cleanup the
             # self._script_dir list when done.
             with open(expanded_path, encoding='utf-8') as target:
-                self.cmdqueue = target.read().splitlines() + ['eos'] + self.cmdqueue
+                script_commands = target.read().splitlines()
         except OSError as ex:  # pragma: no cover
             self.perror("Problem accessing script from '{}': {}".format(expanded_path, ex))
             return
 
+        if args.transcript:
+            self._generate_transcript(script_commands, os.path.expanduser(args.transcript))
+            return
+
+        self.cmdqueue = script_commands + ['eos'] + self.cmdqueue
         self._script_dir.append(os.path.dirname(expanded_path))
 
     relative_load_description = load_description
@@ -3812,7 +3831,7 @@ class Cmd(cmd.Cmd):
 
         # If transcript-based regression testing was requested, then do that instead of the main loop
         if self._transcript_files is not None:
-            self.run_transcript_tests(self._transcript_files)
+            self.run_transcript_tests([os.path.expanduser(tf) for tf in self._transcript_files])
         else:
             # If an intro was supplied in the method call, allow it to override the default
             if intro is not None:
diff --git a/docs/freefeatures.rst b/docs/freefeatures.rst
index 001a7599..11b5de68 100644
--- a/docs/freefeatures.rst
+++ b/docs/freefeatures.rst
@@ -19,6 +19,15 @@ Both ASCII and UTF-8 encoded unicode text files are supported.
 
 Simply include one command per line, typed exactly as you would inside a ``cmd2`` application.
 
+The ``load`` command loads commands from a script file into a queue and then the normal cmd2 REPL
+resumes control and executes the commands in the queue in FIFO order.  A side effect of this
+is that if you redirect/pipe the output of a load command, it will redirect the output of the ``load``
+command itself, but will NOT redirect the output of the command loaded from the script file.  Of course,
+you can add redirection to the commands being run in the script file, e.g.::
+
+    # This is your script file
+    command arg1 arg2 > file.txt
+
 .. automethod:: cmd2.cmd2.Cmd.do_load
 
 .. automethod:: cmd2.cmd2.Cmd.do__relative_load
diff --git a/docs/transcript.rst b/docs/transcript.rst
index 36b35fcf..c7c31fd6 100644
--- a/docs/transcript.rst
+++ b/docs/transcript.rst
@@ -13,9 +13,9 @@ from commands that produce dynamic or variable output.
 Creating a transcript
 =====================
 
-Automatically
--------------
-A transcript can automatically generated based upon commands previously executed in the *history*::
+Automatically from history
+--------------------------
+A transcript can automatically generated based upon commands previously executed in the *history* using ``history -t``::
 
     (Cmd) help
     ...
@@ -32,6 +32,17 @@ This is by far the easiest way to generate a transcript.
    of the ``cmd2.Cmd`` class ensure that output is properly redirected when redirecting to a file, piping to a shell
    command, and when generating a transcript.
 
+Automatically from a script file
+--------------------------------
+A transcript can also be automatically generated from a script file using ``load -t``::
+
+    (Cmd) load scripts/script.txt -t transcript.txt
+    2 commands and their outputs saved to transcript file 'transcript.txt'
+    (Cmd)
+
+This is a particularly attractive option for automatically regenerating transcripts for regression testing as your ``cmd2``
+application changes.
+
 Manually
 --------
 Here's a transcript created from ``python examples/example.py``::

transcript generation/update
Lately I've been working a lot on my program, tinkering with the output and all.
I miss having more tests to check for regression.
I had started creating some transcripts but they got outdated and I am not sure what's the best way to update them (from scratch ?).
Right now I believe the main approach is using `history` and because my program accepts commands from the command line, I can run
`mptcpanalyzer -d DEBUG -l ~/pcaps/tmpatm6409s/client_2_.pcapng "summary_extended ~/pcaps/tmpatm6409s/client_2_.pcapng 1 ~/pcaps/tmpatm6409s/server_2_.pcapng 1" "history 1:1 -t transcript.txt"  "quit"`
but I would love to be able to update transcripts in place. Like for instance I have the following transcript.txt
```
server_2_filtered.pcapng> load_pcap examples/server_2_filtered.pcapng
Loading examples\/server_2_filtered.pcapng
server_2_filtered.pcapng> summary 0 Client
mptcpstream 0 transferred 308 bytes.
tcpstream 0 transferred 308 bytes out of 308, accounting for 100.00%
tcpstream 2 transferred 0 bytes out of 308, accounting for 0.00%
tcpstream 6 transferred 0 bytes out of 308, accounting for 0.00%
server_2_filtered.pcapng> summary 0 Server
mptcpstream 0 transferred 461 bytes.
tcpstream 0 transferred 456 bytes out of 461, accounting for 98.92%
tcpstream 2 transferred 5 bytes out of 461, accounting for 1.08%
tcpstream 6 transferred 0 bytes out of 461, accounting for 0.00%
```
And I could run a command for instance `transcript update transcript.txt` that reruns the commands and updates the outputs accordingly.
diff --git a/tests/scripts/help.txt b/tests/scripts/help.txt
new file mode 100644
index 00000000..71d23d97
--- /dev/null
+++ b/tests/scripts/help.txt
@@ -0,0 +1,1 @@
+help -v
diff --git a/tests/test_transcript.py b/tests/test_transcript.py
index 4a03ebe0..acdbe703 100644
--- a/tests/test_transcript.py
+++ b/tests/test_transcript.py
@@ -17,7 +17,7 @@ from unittest import mock
 import pytest
 
 import cmd2
-from .conftest import run_cmd
+from .conftest import run_cmd, BASE_HELP_VERBOSE
 from cmd2 import transcript
 from cmd2.utils import StdSim
 
@@ -136,7 +136,7 @@ def test_transcript(request, capsys, filename, feedback_to_output):
     assert err.startswith(expected_start)
     assert err.endswith(expected_end)
 
-def test_history_transcript(request, capsys):
+def test_history_transcript():
     app = CmdLineApp()
     app.stdout = StdSim(app.stdout)
     run_cmd(app, 'orate this is\na /multiline/\ncommand;\n')
@@ -163,7 +163,7 @@ this is a \/multiline\/ command
 
     assert xscript == expected
 
-def test_history_transcript_bad_filename(request, capsys):
+def test_history_transcript_bad_filename():
     app = CmdLineApp()
     app.stdout = StdSim(app.stdout)
     run_cmd(app, 'orate this is\na /multiline/\ncommand;\n')
@@ -189,6 +189,35 @@ this is a \/multiline\/ command
             transcript = f.read()
         assert transcript == expected
 
+
+def test_load_record_transcript(base_app, request):
+    test_dir = os.path.dirname(request.module.__file__)
+    filename = os.path.join(test_dir, 'scripts', 'help.txt')
+
+    assert base_app.cmdqueue == []
+    assert base_app._script_dir == []
+    assert base_app._current_script_dir is None
+
+    # make a tmp file to use as a transcript
+    fd, transcript_fname = tempfile.mkstemp(prefix='', suffix='.trn')
+    os.close(fd)
+
+    # Run the load command with the -r option to generate a transcript
+    run_cmd(base_app, 'load {} -t {}'.format(filename, transcript_fname))
+
+    assert base_app.cmdqueue == []
+    assert base_app._script_dir == []
+    assert base_app._current_script_dir is None
+
+    # read in the transcript created by the history command
+    with open(transcript_fname) as f:
+        xscript = f.read()
+
+    expected = '(Cmd) help -v\n' + BASE_HELP_VERBOSE + '\n'
+
+    assert xscript == expected
+
+
 @pytest.mark.parametrize('expected, transformed', [
     # strings with zero or one slash or with escaped slashes means no regular
     # expression present, so the result should just be what re.escape returns.

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest codecov pytest-cov pytest-mock
3.9
requirements/base.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
anyio==4.9.0
astroid==3.3.9
attrs==25.3.0
babel==2.17.0
backports.tarfile==1.2.0
cachetools==5.5.2
certifi==2025.1.31
cffi==1.17.1
chardet==5.2.0
charset-normalizer==3.4.1
click==8.1.8
-e git+https://github.com/python-cmd2/cmd2.git@e89bd4f5e70300251314117d3664ad92c9123ade#egg=cmd2
codecov==2.1.13
colorama==0.4.6
coverage==7.8.0
cryptography==44.0.2
dill==0.3.9
distlib==0.3.9
docutils==0.21.2
exceptiongroup==1.2.2
filelock==3.18.0
h11==0.14.0
id==1.5.0
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
iniconfig==2.1.0
invoke==2.2.0
isort==6.0.1
jaraco.classes==3.4.0
jaraco.context==6.0.1
jaraco.functools==4.1.0
jeepney==0.9.0
Jinja2==3.1.6
keyring==25.6.0
markdown-it-py==3.0.0
MarkupSafe==3.0.2
mccabe==0.7.0
mdurl==0.1.2
more-itertools==10.6.0
nh3==0.2.21
packaging==24.2
platformdirs==4.3.7
pluggy==1.5.0
pycparser==2.22
Pygments==2.19.1
pylint==3.3.6
pyperclip==1.9.0
pyproject-api==1.9.0
pytest==8.3.5
pytest-cov==6.0.0
pytest-mock==3.14.0
readme_renderer==44.0
requests==2.32.3
requests-toolbelt==1.0.0
rfc3986==2.0.0
rich==14.0.0
SecretStorage==3.3.3
sniffio==1.3.1
snowballstemmer==2.2.0
Sphinx==7.4.7
sphinx-autobuild==2024.10.3
sphinx-rtd-theme==3.0.2
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jquery==4.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
starlette==0.46.1
tomli==2.2.1
tomlkit==0.13.2
tox==4.25.0
twine==6.1.0
typing_extensions==4.13.0
urllib3==2.3.0
uvicorn==0.34.0
virtualenv==20.29.3
watchfiles==1.0.4
wcwidth==0.2.13
websockets==15.0.1
zipp==3.21.0

name: cmd2
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - anyio==4.9.0
      - astroid==3.3.9
      - attrs==25.3.0
      - babel==2.17.0
      - backports-tarfile==1.2.0
      - cachetools==5.5.2
      - certifi==2025.1.31
      - cffi==1.17.1
      - chardet==5.2.0
      - charset-normalizer==3.4.1
      - click==8.1.8
      - codecov==2.1.13
      - colorama==0.4.6
      - coverage==7.8.0
      - cryptography==44.0.2
      - dill==0.3.9
      - distlib==0.3.9
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - filelock==3.18.0
      - h11==0.14.0
      - id==1.5.0
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - invoke==2.2.0
      - isort==6.0.1
      - jaraco-classes==3.4.0
      - jaraco-context==6.0.1
      - jaraco-functools==4.1.0
      - jeepney==0.9.0
      - jinja2==3.1.6
      - keyring==25.6.0
      - markdown-it-py==3.0.0
      - markupsafe==3.0.2
      - mccabe==0.7.0
      - mdurl==0.1.2
      - more-itertools==10.6.0
      - nh3==0.2.21
      - packaging==24.2
      - platformdirs==4.3.7
      - pluggy==1.5.0
      - pycparser==2.22
      - pygments==2.19.1
      - pylint==3.3.6
      - pyperclip==1.9.0
      - pyproject-api==1.9.0
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - pytest-mock==3.14.0
      - readme-renderer==44.0
      - requests==2.32.3
      - requests-toolbelt==1.0.0
      - rfc3986==2.0.0
      - rich==14.0.0
      - secretstorage==3.3.3
      - sniffio==1.3.1
      - snowballstemmer==2.2.0
      - sphinx==7.4.7
      - sphinx-autobuild==2024.10.3
      - sphinx-rtd-theme==3.0.2
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jquery==4.1
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - starlette==0.46.1
      - tomli==2.2.1
      - tomlkit==0.13.2
      - tox==4.25.0
      - twine==6.1.0
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - uvicorn==0.34.0
      - virtualenv==20.29.3
      - watchfiles==1.0.4
      - wcwidth==0.2.13
      - websockets==15.0.1
      - zipp==3.21.0
prefix: /opt/conda/envs/cmd2

tests/test_transcript.py::test_load_record_transcript
tests/test_transcript.py::test_commands_at_invocation tests/test_transcript.py::test_transcript[bol_eol.txt-False] tests/test_transcript.py::test_transcript[characterclass.txt-False] tests/test_transcript.py::test_transcript[dotstar.txt-False] tests/test_transcript.py::test_transcript[extension_notation.txt-False] tests/test_transcript.py::test_transcript[from_cmdloop.txt-True] tests/test_transcript.py::test_transcript[multiline_no_regex.txt-False] tests/test_transcript.py::test_transcript[multiline_regex.txt-False] tests/test_transcript.py::test_transcript[no_output.txt-False] tests/test_transcript.py::test_transcript[no_output_last.txt-False] tests/test_transcript.py::test_transcript[regex_set.txt-False] tests/test_transcript.py::test_transcript[singleslash.txt-False] tests/test_transcript.py::test_transcript[slashes_escaped.txt-False] tests/test_transcript.py::test_transcript[slashslash.txt-False] tests/test_transcript.py::test_transcript[spaces.txt-False] tests/test_transcript.py::test_transcript[word_boundaries.txt-False] tests/test_transcript.py::test_history_transcript tests/test_transcript.py::test_history_transcript_bad_filename tests/test_transcript.py::test_parse_transcript_expected[text tests/test_transcript.py::test_parse_transcript_expected[specials tests/test_transcript.py::test_parse_transcript_expected[use tests/test_transcript.py::test_parse_transcript_expected[/tmp tests/test_transcript.py::test_parse_transcript_expected[slash tests/test_transcript.py::test_parse_transcript_expected[not tests/test_transcript.py::test_parse_transcript_expected[/.*/-.*] tests/test_transcript.py::test_parse_transcript_expected[/a{6}/ tests/test_transcript.py::test_parse_transcript_expected[lots
cmd2/cmd2.py docs/transcript.rst docs/freefeatures.rst CHANGELOG.md
cmd2/cmd2.py docs/transcript.rst docs/freefeatures.rst CHANGELOG.md